-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmain.go
354 lines (342 loc) · 12.7 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
package main
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"github.com/1pkg/gopium/gopium"
"github.com/1pkg/gopium/runners"
"github.com/spf13/cobra"
)
// list of all cli vars
var (
// cli command iteself
cli *cobra.Command
// target platform vars
tcompiler string
tarch string
tcpulines []int
// package parser vars
ppath string
pbenvs []string
pbflags []string
// gopium walker vars
wregex string
wdeep bool
wbackref bool
// gopium printer vars
pindent int
ptabwidth int
pusespace bool
pusegofmt bool
// gopium global vars
timeout int
)
// init cli command runner
// and global context
func init() {
// set root cli command app
cli = &cobra.Command{
Use: "gopium -flag_0 -flag_n walker package strategy_1 strategy_2 strategy_3 ...",
Short: gopium.STAMP,
Version: gopium.VERSION,
Example: "gopium -r ^A go_std 1pkg/gopium filter_pads memory_pack separate_padding_cpu_l1_top separate_padding_cpu_l1_bottom",
Long: `
Gopium is the tool that was designed to automate and simplify some common performance transformations for structs, such as:
- cpu cache alignment
- memory packing
- false sharing guarding
- auto annotation
- generic fields management, etc.
In order to use gopium cli you need to provide at least package name (full package name is expected),
list of strategies which is applied one by one and single walker.
Outcome of execution is fully defined by list of strategies and walker combination.
List of strategies modifies structs inside the package, walker facilitates and insures,
that outcome is formatted and written to one of provided destinations.
Gopium provides next walkers:
- ast_go (directly syncs result as go code to orinal file)
- ast_go_tree (directly syncs result as go code to copy package)
- ast_std (prints result as go code to stdout)
- ast_gopium (directly syncs result as go code to copy gopium files)
- file_json (prints json encoded results to single file inside package directory)
- file_xml (prints xml encoded results to single file inside package directory)
- file_csv (prints csv encoded results to single file inside package directory)
- file_md_table (prints markdown table encoded results to single file inside package directory)
- size_align_file_md_table (prints markdown encoded table of sizes and aligns difference for results to single file
inside package directory)
- fields_file_html_table (prints html encoded table of fields difference for results to single file
inside package directory)
Gopium provides next strategies:
- process_tag_group (uses gopium fields tags annotation in order to process different set of strategies
on different groups and then combine results in single struct result)
- memory_pack (rearranges structure fields to obtain optimal memory utilization)
- memory_unpack (rearranges structure field list to obtain inflated memory utilization)
- cache_rounding_cpu_l1_discrete (fits structure into cpu cache line #1 by adding bottom partial rounding cpu cache padding)
- cache_rounding_cpu_l2_discrete (fits structure into cpu cache line #2 by adding bottom partial rounding cpu cache padding)
- cache_rounding_cpu_l3_discrete (fits structure into cpu cache line #3 by adding bottom partial rounding cpu cache padding)
- cache_rounding_bytes_{{uint}}_discrete (fits structure into provided number of bytes by adding bottom partial rounding
bytes cache padding)
- cache_rounding_cpu_l1_full (fits structure into full cpu cache line #1 by adding bottom rounding cpu cache padding)
- cache_rounding_cpu_l2_full (fits structure into full cpu cache line #2 by adding bottom rounding cpu cache padding)
- cache_rounding_cpu_l3_full (fits structure into full cpu cache line #3 by adding bottom rounding cpu cache padding)
- cache_rounding_bytes_{{uint}}_full (fits structure into full provided number of bytes by adding bottom rounding
bytes cache padding)
- false_sharing_cpu_l1 (guards structure from false sharing by adding extra cpu cache line #1 paddings
for each structure field)
- false_sharing_cpu_l2 (guards structure from false sharing by adding extra cpu cache line #1 paddings
for each structure field)
- false_sharing_cpu_l3 (guards structure from false sharing by adding extra cpu cache line #1 paddings
for each structure field)
- false_sharing_bytes_{{uint}} (guards structure from false sharing by adding extra provided number of bytes paddings
for each structure field)
- separate_padding_system_alignment_top (separates structure with extra system alignment padding by adding
the padding at the top)
- separate_padding_system_alignment_bottom (separates structure with extra system alignment padding by adding
the padding at the bottom)
- separate_padding_cpu_l1_top (separates structure with extra cpu cache line #1 padding by adding
the padding at the top)
- separate_padding_cpu_l2_top (separates structure with extra cpu cache line #2 padding by adding
the padding at the top)
- separate_padding_cpu_l3_top (separates structure with extra cpu cache line #3 padding by adding
the padding at the top)
- separate_padding_bytes_{{uint}_top (separates structure with extra provided number of bytes padding by adding
the padding at the top)
- separate_padding_cpu_l1_bottom (separates structure with extra cpu cache line #1 padding by adding
the padding at the bottom)
- separate_padding_cpu_l2_bottom (separates structure with extra cpu cache line #2 padding by adding
the padding at the bottom)
- separate_padding_cpu_l3_bottom (separates structure with extra cpu cache line #3 padding by adding
the padding at the bottom)
- separate_padding_bytes_{{uint}_bottom (separates structure with extra provided number of bytes padding by adding
the padding at the bottom)
- explicit_paddings_system_alignment (explicitly aligns each structure field to system alignment padding by adding
missing paddings for each field)
- explicit_paddings_type_natural (explicitly aligns each structure field to max type alignment padding by adding
missing paddings for each field)
- add_tag_group_soft (adds gopium fields tags annotation if no previous annotation found)
- add_tag_group_force (adds gopium fields tags annotation if previous annotation found overwrites it)
- add_tag_group_discrete (discretely adds gopium fields tags annotation if no previous annotation found)
- add_tag_group_force_discrete (discretely adds gopium fields tags annotation if previous annotation
found overwrites it)
- remove_tag_group (removes gopium fields tags annotation)
- fields_annotate_doc (adds align and size doc annotation for each structure field)
- fields_annotate_comment adds align and size comment annotation for each structure field)
- struct_annotate_doc (adds aggregated align and size doc annotation for structure)
- struct_annotate_comment (adds aggregated align and size comment annotation for structure)
- name_lexicographical_ascending (sorts fields accordingly to their names in ascending order)
- name_lexicographical_descending (sorts fields accordingly to their names descending order)
- type_lexicographical_ascending (sorts fields accordingly to their types in ascending order)
- type_lexicographical_descending (sorts fields accordingly to their types in descending order)
- filter_pads (filters out all structure padding fields)
- ignore (does nothing by returning original structure)
Notes:
- it might be useful to use filter_pads in pipes with other strategies to clean paddings first.
- process_tag_group currently supports only next fields tags annotation formats:
- gopium:"stg,stg,stg" processed as default group
- gopium:"group:def;stg,stg,stg" processed as named group
- by specifying tag_type you can automatically generate fields tags annotation suitable for process_tag_group.
- add_tag_* strategies just add list of applied transformations to structure fields tags and NOT change results of
other strategies, you can execute process_tag_group strategy afterwards to reuse saved strategies list.
`,
Args: cobra.MinimumNArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
// create cli app instance
cli, err := runners.NewCli(
// target platform vars
tcompiler,
tarch,
tcpulines,
// package parser vars
args[1], // package name
ppath,
defenv(cmd.Context(), pbenvs, "GOPATH", "GOCACHE", "GOTMPDIR"),
pbflags,
// gopium walker vars
args[0], // single walker
wregex,
wdeep,
wbackref,
args[2:], // strategies slice
// gopium printer vars
pindent,
ptabwidth,
pusespace,
pusegofmt,
// gopium global vars
timeout,
)
if err != nil {
return err
}
// execute app
return cli.Run(cmd.Context())
},
}
// set target_compiler flag
cli.Flags().StringVarP(
&tcompiler,
"target_compiler",
"c",
"gc",
"Gopium target platform compiler, possible values are: gc or gccgo.",
)
// set target_architecture flag
cli.Flags().StringVarP(
&tarch,
"target_architecture",
"a",
"amd64",
"Gopium target platform architecture, possible values are: 386, arm, arm64, amd64, mips, etc.",
)
// set target_cpu_cache_lines_sizes flag
cli.Flags().IntSliceVarP(
&tcpulines,
"target_cpu_cache_lines_sizes",
"l",
[]int{64, 64, 64},
`
Gopium target platform CPU cache line sizes in bytes, cache line size is set one by one l1,l2,l3,...
For now only 3 lines of cache are supported by strategies.
`,
)
// set package_path flag
cli.Flags().StringVarP(
&ppath,
"package_path",
"p",
filepath.Join("src", "{{package}}"),
`
Gopium go package path, either relative or absolute path to root of the package is expected.
To obtain full path from relative, package path is concatenated with current GOPATH env var.
Template {{package}} part is replaced with package name.
`,
)
// set package_build_envs flag
cli.Flags().StringSliceVarP(
&pbenvs,
"package_build_envs",
"e",
[]string{},
"Gopium go package build envs, additional list of building envs is expected.",
)
// set package_build_flags flag
cli.Flags().StringSliceVarP(
&pbflags,
"package_build_flags",
"f",
[]string{},
"Gopium go package build flags, additional list of building flags is expected.",
)
// set walker_regexp flag
cli.Flags().StringVarP(
&wregex,
"walker_regexp",
"r",
".*",
`
Gopium walker regexp, regexp that defines which structures are subjects for visiting.
Visiting is done only if structure name matches the regexp.
`,
)
// set walker_deep flag
cli.Flags().BoolVarP(
&wdeep,
"walker_deep",
"d",
true,
`
Gopium walker deep flag, flag that defines type of nested scopes visiting.
By default it visits all nested scopes.
`,
)
// set walker_backref flag
cli.Flags().BoolVarP(
&wbackref,
"walker_backref",
"b",
true,
`
Gopium walker backref flag, flag that defines type of names referencing.
By default any previous visited types have affect on future relevant visits.
`,
)
// set printer_indent flag
cli.Flags().IntVarP(
&pindent,
"printer_indent",
"i",
0,
"Gopium printer width of tab, defines the least code indent.",
)
// set printer_tab_width flag
cli.Flags().IntVarP(
&ptabwidth,
"printer_tab_width",
"w",
8,
"Gopium printer width of tab, defines width of tab in spaces for printer.",
)
// set printer_use_space flag
cli.Flags().BoolVarP(
&pusespace,
"printer_use_space",
"s",
false,
"Gopium printer use space flag, flag that defines if all formatting should be done by spaces.",
)
// set printer_use_gofmt flag
cli.Flags().BoolVarP(
&pusegofmt,
"printer_use_gofmt",
"g",
true,
`
Gopium printer use gofmt flag, flag that defines if canonical gofmt tool should be used for formatting.
By default it is used and overrides other printer formatting parameters.
`,
)
// set timeout flag
cli.Flags().IntVarP(
&timeout,
"timeout",
"t",
0,
"Gopium global timeout of cli command in seconds, considered only if value greater than 0.",
)
}
// defenv appends requested env variable from `go env`, if no custom variable provided
func defenv(ctx context.Context, envs []string, vars ...string) []string {
loop:
for _, v := range vars {
for _, env := range envs {
if strings.HasPrefix(env, v) {
continue loop
}
}
ebytes, err := exec.CommandContext(ctx, "go", "env", v).CombinedOutput()
if err == nil {
envs = append(envs, fmt.Sprintf("%s=%s", v, strings.TrimSpace(string(ebytes))))
}
}
return envs
}
// main gopium cli entry point
func main() {
// explicitly set number of threads
// to number of logical cpu
runtime.GOMAXPROCS(runtime.NumCPU())
// prepare context with signals cancelation
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
// execute cobra cli command
// with ctx and log error if any
if err := cli.ExecuteContext(ctx); err != nil {
log.Fatal(err)
os.Exit(1)
}
}