Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Significant performance regression since 1.62 #5546

Open
6 of 7 tasks
pfouilloux opened this issue Mar 14, 2025 · 18 comments
Open
6 of 7 tasks

Significant performance regression since 1.62 #5546

pfouilloux opened this issue Mar 14, 2025 · 18 comments
Assignees
Labels
feedback required Requires additional feedback platform: macos Issue that is related to MacOS question Further information is requested topic: speed

Comments

@pfouilloux
Copy link

pfouilloux commented Mar 14, 2025

Welcome

  • Yes, I'm using a binary release within 2 latest releases. Only such installations are supported.
  • Yes, I've searched similar issues on GitHub and didn't find any.
  • Yes, I've read the typecheck section of the FAQ.
  • Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.).
  • I agree to follow this project's Code of Conduct

How did you install golangci-lint?

Other

Description of the problem

We've been struggling with very long lint times on our project, and one of our team members noticed performance was much better on version 1.61...

The examples below are a bit contrived as they are without cache. The cache does help but it's still not uncommon to see times >1min on an M4 Macbook Pro with 32GB ram when touching files that are near the root of the dependency tree, it's just a bit of a pain to benchmark that reliably.

It's even worse for team members on older hardware, with some reporting linting taking up to 10 minutes on M1/16GB Macbooks.

I've done a couple of quick benchmarks to illustrate:

Notice that the latest version is 1.5x-2x slower than 1.61.0
We've narrowed it down to somewhere between 1.61.0 and 1.62.2.

I'd be happy to have a go at improving this, but could use some assistance if there are some obvious places to check and/or updated packages that are more likely to be where the degradation is coming from.

I've used mise.jdx.dev to quickly switch between versions but we're vendoring in golangci-lint from the official binary normally.

v1.64.7 - our repo - 94.36s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [goenv] Read go env for 5.38825ms: map[string]string{"GOCACHE":"/Users/pfx/Library/Caches/go-build", "GOROOT":"/Users/pfx/.local/share/mise/installs/go/1.23.6"} 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (compiled_files|deps|exports_file|name|types_sizes|files|imports) took 1.466605s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 127.481083ms 
INFO [linters_context/goanalysis] analyzers took 1h15m46.143915518s with top 10 stages: buildir: 8m42.547657609s, goimports: 5m23.94896072s, the_only_name: 3m51.560881539s, unconvert: 2m26.072338515s, gocritic: 1m11.835696217s, gci: 57.167173259s, buildssa: 57.132585509s, gofmt: 51.003987963s, S1038: 50.016766632s, nilness: 34.707608705s 
INFO [runner/exclusion_rules] Skipped 1 issues by rules: [Source: "(?i)^//\\$\\(which go\\)", Linters: "gocritic"] 
INFO [runner] Issues before processing: 12730, after processing: 0 
INFO [runner] Processors filtering stat (in/out): filename_unadjuster: 12730/12730, path_relativity: 12730/12730, exclusion_paths: 12730/12730, exclusion_rules: 12730/32, path_absoluter: 12730/12730, cgo: 12730/12730, skip_dirs: 12730/12730, generated_file_filter: 12730/12730, identifier_marker: 12730/12730, nolint_filter: 32/0, invalid_issue: 12730/12730, skip_files: 12730/12730 
INFO [runner] processing took 92.27958ms with stages: generated_file_filter: 40.326083ms, exclusion_rules: 34.347916ms, skip_dirs: 5.796208ms, nolint_filter: 4.588584ms, path_relativity: 4.457083ms, invalid_issue: 829.332µs, cgo: 651.333µs, path_absoluter: 592.666µs, identifier_marker: 389.291µs, filename_unadjuster: 298.083µs, max_same_issues: 583ns, exclusion_paths: 501ns, sort_results: 459ns, fixer: 334ns, path_shortener: 167ns, diff: 167ns, skip_files: 125ns, source_code: 125ns, path_prettifier: 125ns, uniq_by_line: 125ns, max_from_linter: 124ns, max_per_file_from_linter: 83ns, severity-rules: 83ns 
INFO [runner] linters took 1m32.621252209s with stages: goanalysis_metalinter: 1m32.528679083s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 856 samples, avg is 3342.7MB, max is 5435.0MB 
INFO Execution took 1m34.23183775s                

________________________________________________________
Executed in   94.36 secs    fish           external
   usr time  209.44 secs   29.00 micros  209.44 secs
   sys time  208.56 secs  320.00 micros  208.56 secs
v1.64.7 - golangci-lint repo - 13.96s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/3-resources/golangci-lint /Users/pfx/code/3-resources /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [goenv] Read go env for 5.256333ms: map[string]string{"GOCACHE":"/Users/pfx/Library/Caches/go-build", "GOROOT":"/Users/pfx/.local/share/mise/installs/go/1.24.1"} 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (compiled_files|exports_file|imports|deps|files|name|types_sizes) took 739.015709ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 10.975208ms 
INFO [linters_context/goanalysis] analyzers took 4m51.309911657s with top 10 stages: buildir: 1m12.353763424s, the_only_name: 23.068014253s, goimports: 20.804942005s, unconvert: 9.847325041s, fact_deprecated: 5.849002084s, exhaustive: 5.800382049s, gocritic: 5.37269097s, printf: 4.918556524s, ctrlflow: 4.533309826s, inspect: 4.352578737s 
INFO [runner/exclusion_rules] Skipped 0 issues by rules: [Source: "(?i)^//\\$\\(which go\\)", Linters: "gocritic"] 
INFO [runner] Issues before processing: 1692, after processing: 507 
INFO [runner] Processors filtering stat (in/out): path_relativity: 1692/1692, exclusion_paths: 1692/1692, generated_file_filter: 1692/1692, exclusion_rules: 1692/721, uniq_by_line: 717/709, severity-rules: 507/507, filename_unadjuster: 1692/1692, skip_dirs: 1692/1692, nolint_filter: 721/717, diff: 717/717, max_from_linter: 507/507, path_absoluter: 1692/1692, fixer: 717/717, max_same_issues: 507/507, skip_files: 1692/1692, identifier_marker: 1692/1692, max_per_file_from_linter: 709/507, source_code: 507/507, path_shortener: 507/507, path_prettifier: 507/507, sort_results: 507/507, cgo: 1692/1692, invalid_issue: 1692/1692 
INFO [runner] processing took 40.778542ms with stages: nolint_filter: 18.315292ms, generated_file_filter: 8.054291ms, exclusion_rules: 7.948125ms, source_code: 3.874584ms, skip_dirs: 844.501µs, path_relativity: 609.875µs, sort_results: 545.875µs, uniq_by_line: 108.208µs, invalid_issue: 82µs, cgo: 78.708µs, path_absoluter: 78.375µs, identifier_marker: 72.333µs, max_per_file_from_linter: 56.833µs, path_shortener: 52.25µs, filename_unadjuster: 40.75µs, path_prettifier: 14.5µs, max_same_issues: 707ns, exclusion_paths: 375ns, fixer: 293ns, max_from_linter: 208ns, severity-rules: 167ns, skip_files: 167ns, diff: 125ns 
INFO [runner] linters took 13.1195375s with stages: goanalysis_metalinter: 13.078657625s 
INFO File cache stats: 364 entries of total size 791.6KiB 
INFO Memory: 140 samples, avg is 988.9MB, max is 1386.7MB 
INFO Execution took 13.882652917s                 

________________________________________________________
Executed in   13.96 secs    fish           external
   usr time   46.60 secs   28.00 micros   46.60 secs
   sys time   36.50 secs  290.00 micros   36.50 secs

v1.61.0 - our repo - 30.48s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (deps|imports|name|types_sizes|compiled_files|files|exports_file) took 1.232954542s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 122.858917ms 
INFO [linters_context/goanalysis] analyzers took 16m46.333819152s with top 10 stages: buildir: 2m32.081693002s, the_only_name: 1m16.605160047s, unconvert: 48.191368608s, gci: 33.988684293s, goimports: 30.439255918s, buildssa: 27.443786584s, gocritic: 20.463837861s, gofmt: 19.537270587s, S1038: 16.578077052s, fact_deprecated: 13.950451036s 
INFO [runner] Issues before processing: 12734, after processing: 0 
INFO [runner] Processors filtering stat (in/out): nolint: 32/0, invalid_issue: 12734/12734, skip_dirs: 12734/12734, identifier_marker: 12734/12734, cgo: 12734/12734, exclude-rules: 12734/32, filename_unadjuster: 12734/12734, path_prettifier: 12734/12734, skip_files: 12734/12734, autogenerated_exclude: 12734/12734, exclude: 12734/12734 
INFO [runner] processing took 551.290668ms with stages: autogenerated_exclude: 222.735042ms, exclude-rules: 178.508584ms, identifier_marker: 111.570542ms, path_prettifier: 26.301792ms, skip_dirs: 5.5495ms, nolint: 4.612708ms, cgo: 788.5µs, invalid_issue: 764.916µs, filename_unadjuster: 456.5µs, sort_results: 1.084µs, max_same_issues: 375ns, uniq_by_line: 249ns, diff: 167ns, skip_files: 166ns, fixer: 125ns, max_per_file_from_linter: 84ns, max_from_linter: 83ns, exclude: 83ns, path_shortener: 42ns, path_prefixer: 42ns, source_code: 42ns, severity-rules: 42ns 
INFO [runner] linters took 28.966006458s with stages: goanalysis_metalinter: 28.414657167s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 300 samples, avg is 3108.3MB, max is 5292.8MB 
INFO Execution took 30.331369708s                 

________________________________________________________
Executed in   30.48 secs    fish           external
   usr time  207.87 secs   41.00 micros  207.87 secs
   sys time   30.33 secs  352.00 micros   30.33 secs
v1.61.0 - golangci-lint repo - 7.28s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/3-resources/golangci-lint /Users/pfx/code/3-resources /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (compiled_files|name|types_sizes|deps|exports_file|files|imports) took 568.71375ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 11.621ms 
INFO [linters_context/goanalysis] analyzers took 2m40.209582595s with top 10 stages: SA5012: 2.128580502s, nilness: 1.946276669s, SA1028: 1.686747091s, SA1024: 1.548594294s, SA5011: 1.507124704s, exhaustive: 1.470268658s, ctrlflow: 1.46878338s, SA1023: 1.448945918s, SA1003: 1.434683541s, SA6001: 1.425019419s 
INFO [runner] Issues before processing: 35161, after processing: 187 
INFO [runner] Processors filtering stat (in/out): exclude-rules: 35154/35154, uniq_by_line: 35154/187, max_from_linter: 187/187, path_shortener: 187/187, severity-rules: 187/187, filename_unadjuster: 35161/35161, skip_files: 35154/35154, fixer: 187/187, nolint: 35154/35154, diff: 187/187, identifier_marker: 35154/35154, exclude: 35154/35154, max_per_file_from_linter: 187/187, max_same_issues: 187/187, path_prefixer: 187/187, cgo: 35161/35161, invalid_issue: 35161/35154, autogenerated_exclude: 35154/35154, source_code: 187/187, sort_results: 187/187, path_prettifier: 35154/35154, skip_dirs: 35154/35154 
INFO [runner] processing took 194.384832ms with stages: identifier_marker: 180.004375ms, path_prettifier: 7.5295ms, autogenerated_exclude: 2.596916ms, source_code: 878.167µs, skip_dirs: 602µs, uniq_by_line: 518.5µs, filename_unadjuster: 498.958µs, invalid_issue: 476.708µs, nolint: 470.958µs, cgo: 470.375µs, exclude-rules: 291.626µs, sort_results: 33.333µs, path_shortener: 8.708µs, max_per_file_from_linter: 3.376µs, max_same_issues: 375ns, fixer: 251ns, skip_files: 249ns, exclude: 208ns, diff: 166ns, max_from_linter: 83ns, path_prefixer: 0s, severity-rules: 0s 
INFO [runner] linters took 6.614266333s with stages: goanalysis_metalinter: 6.419802625s 
INFO File cache stats: 52 entries of total size 268.5KiB 
INFO Memory: 74 samples, avg is 1585.9MB, max is 2155.2MB 
INFO Execution took 7.202327208s                  

________________________________________________________
Executed in    7.28 secs    fish           external
   usr time   18.55 secs   47.00 micros   18.55 secs
   sys time    6.36 secs  519.00 micros    6.36 secs

v1.62.2 - our repo - 98.60s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (types_sizes|compiled_files|imports|name|deps|exports_file|files) took 1.327498291s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 131.053334ms 
INFO [linters_context/goanalysis] analyzers took 1h8m32.901853981s with top 10 stages: buildir: 9m24.29088962s, goimports: 5m44.991186468s, the_only_name: 4m17.010925691s, unconvert: 2m37.044259555s, gci: 1m39.809556491s, gocritic: 1m5.701493456s, S1038: 58.342486334s, buildssa: 57.010763741s, gofmt: 45.747209843s, nilness: 31.878821318s 
INFO [runner] Issues before processing: 12732, after processing: 0 
INFO [runner] Processors filtering stat (in/out): autogenerated_exclude: 12732/12732, identifier_marker: 12732/12732, exclude-rules: 12732/32, skip_files: 12732/12732, filename_unadjuster: 12732/12732, cgo: 12732/12732, exclude: 12732/12732, path_prettifier: 12732/12732, skip_dirs: 12732/12732, nolint: 32/0, invalid_issue: 12732/12732 
INFO [runner] processing took 365.183541ms with stages: exclude-rules: 179.636333ms, identifier_marker: 103.203583ms, autogenerated_exclude: 40.551667ms, path_prettifier: 29.495084ms, skip_dirs: 5.52225ms, nolint: 4.782542ms, invalid_issue: 905µs, cgo: 709.875µs, filename_unadjuster: 373.708µs, max_same_issues: 833ns, sort_results: 708ns, fixer: 333ns, skip_files: 292ns, exclude: 249ns, diff: 209ns, uniq_by_line: 207ns, max_from_linter: 168ns, source_code: 167ns, max_per_file_from_linter: 126ns, path_prefixer: 83ns, severity-rules: 83ns, path_shortener: 41ns 
INFO [runner] linters took 1m37.007741375s with stages: goanalysis_metalinter: 1m36.642083042s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 850 samples, avg is 3482.6MB, max is 5375.6MB 
INFO Execution took 1m38.476208375s               

________________________________________________________
Executed in   98.60 secs    fish           external
   usr time  227.91 secs   30.00 micros  227.91 secs
   sys time  212.68 secs  318.00 micros  212.68 secs
v1.62.2 - golangci-lint repo - 14.85
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/3-resources/golangci-lint /Users/pfx/code/3-resources /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (name|types_sizes|compiled_files|exports_file|imports|deps|files) took 707.264917ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 11.109042ms 
INFO [linters_context/goanalysis] analyzers took 5m30.715674987s with top 10 stages: buildir: 1m25.380368252s, goimports: 24.455756046s, the_only_name: 16.965053422s, unconvert: 11.006405117s, gci: 9.865992166s, gocritic: 7.403908004s, fact_deprecated: 6.79777734s, exhaustive: 6.253641751s, inspect: 5.580758556s, printf: 5.428318296s 
INFO [runner] Issues before processing: 1691, after processing: 708 
INFO [runner] Processors filtering stat (in/out): filename_unadjuster: 1691/1691, invalid_issue: 1691/1691, path_prettifier: 1691/1691, skip_files: 1691/1691, skip_dirs: 1691/1691, exclude: 1691/1691, uniq_by_line: 716/708, max_same_issues: 708/708, fixer: 708/708, sort_results: 708/708, exclude-rules: 1691/720, nolint: 720/716, diff: 708/708, max_from_linter: 708/708, path_prefixer: 708/708, max_per_file_from_linter: 708/708, path_shortener: 708/708, cgo: 1691/1691, autogenerated_exclude: 1691/1691, identifier_marker: 1691/1691, source_code: 708/708, severity-rules: 708/708 
INFO [runner] processing took 68.001703ms with stages: exclude-rules: 21.502458ms, nolint: 17.134583ms, identifier_marker: 11.470291ms, autogenerated_exclude: 7.751666ms, path_prettifier: 4.560917ms, source_code: 3.691458ms, skip_dirs: 836.166µs, sort_results: 661.75µs, cgo: 112.542µs, uniq_by_line: 89.083µs, invalid_issue: 79.708µs, path_shortener: 51.958µs, filename_unadjuster: 42.083µs, max_per_file_from_linter: 15.043µs, max_same_issues: 833ns, diff: 250ns, skip_files: 250ns, max_from_linter: 208ns, severity-rules: 166ns, fixer: 166ns, exclude: 83ns, path_prefixer: 41ns 
INFO [runner] linters took 14.034032s with stages: goanalysis_metalinter: 13.965913208s 
INFO File cache stats: 357 entries of total size 759.8KiB 
INFO Memory: 146 samples, avg is 905.3MB, max is 1116.3MB 
INFO Execution took 14.760288791s                 

________________________________________________________
Executed in   14.85 secs    fish           external
   usr time   50.16 secs   30.00 micros   50.16 secs
   sys time   34.69 secs  337.00 micros   34.69 secs

Version of golangci-lint

$ golangci-lint --version
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z```

Configuration

# Clearing the cache for apples to apples comparison of running time. Performance still very much slower than 1.61 with cache.
golangci-lint cache clean && time golangci-lint run -v
run:
  allow-parallel-runners: true
  build-tags:
    - integration
  timeout: 5m

output:
  sort-results: true

linters:
  disable-all: true
  enable:
    - dogsled
    - errcheck
    - exhaustive
    - gci
    - gocritic
    - gofmt
    - goimports
    - revive
    - goprintffuncname
    - gosimple
    - govet
    - makezero
    - predeclared
    - staticcheck
    - testpackage
    - tparallel
    - typecheck
    - unconvert
    - depguard
    - unused
    - rowserrcheck

linters-settings:
  rowserrcheck:
    packages:
      - github.com/jackc/pgx/v5
  errcheck:
    check-blank: false # Will be enabled in a follow-up commit
  depguard:
    rules:
      main:
        list-mode: lax
        files:
          - "**/handler/**/main.go"
        allow:
          - $gostd
        deny:
          - pkg: "github.com/aws/aws-lambda-go/lambda"
            desc: The usage of this package here is probably a mistake. If you're trying to call lambda.start change it to modules/defaults.start instead (check out other handlers for a complete example). If this is a false positive, please tweak this rule on .golangci.yml

issues:
  max-issues-per-linter: 0
  max-same-issues: 0
  exclude-rules:
    - source: "^//\\$\\(which go\\)"
      linters:
        - gocritic

Go environment

$ go version && go env
GO111MODULE=''
GOARCH='arm64'
GOBIN='/Users/pfx/.local/share/mise/installs/go/1.23.6/bin'
GOCACHE='/Users/pfx/Library/Caches/go-build'
GOENV='/Users/pfx/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/pfx/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/pfx/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/pfx/.local/share/mise/installs/go/1.23.6'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/pfx/.local/share/mise/installs/go/1.23.6/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.6'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/pfx/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/pfx/code/2-areas/platform/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/sy/2gb8vxt11bxcxv0tjywtfz480000gn/T/go-build256349768=/tmp/go-build -gno-record-gcc-switches -fno-common'

Verbose output of running

$ golangci-lint cache clean
$ golangci-lint run -v
# paste output here

A minimal reproducible example or link to a public repository

I copied the config above into the golangci-lint repo and ran the lints here.
It's less glaring because our repo is larger, but we can still see the time is almost doubled on versions > 1.61

Validation

  • Yes, I've included all information above (version, config, etc.).

Supporter

@pfouilloux pfouilloux added the bug Something isn't working label Mar 14, 2025
Copy link

boring-cyborg bot commented Mar 14, 2025

Hey, thank you for opening your first Issue ! 🙂 If you would like to contribute we have a guide for contributors.

@ldez ldez self-assigned this Mar 14, 2025
@ldez
Copy link
Member

ldez commented Mar 14, 2025

Hello,

I don't observe the same things:

v1.64.7 - golangci-lint repo - 8.55s
$ go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
go version go1.23.7 linux/amd64
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /home/ldez/sources/golangci/golangci-lint /home/ldez/sources/golangci /home/ldez/sources /home/ldez /home /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [goenv] Read go env for 2.01233ms: map[string]string{"GOCACHE":"/home/ldez/.cache/go-build", "GOROOT":"/home/ldez/.gvm/gos/go1.23.7"} 
INFO [lintersdb] Active 33 linters: [bodyclose copyloopvar depguard dogsled dupl errcheck errorlint funlen gocheckcompilerdirectives gochecknoinits goconst gocritic gocyclo godox goprintffuncname gosec gosimple govet ineffassign intrange lll misspell mnd nakedret noctx nolintlint revive staticcheck testifylint unconvert unparam unused whitespace] 
INFO [loader] Go packages loading at mode 8767 (deps|imports|types_sizes|compiled_files|exports_file|files|name) took 832.117503ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 9.377495ms 
INFO [linters_context/goanalysis] analyzers took 2m59.879765215s with top 10 stages: buildir: 1m2.560941917s, the_only_name: 12.101747159s, dupl: 6.016083621s, unconvert: 3.629714477s, gocritic: 2.978675605s, fact_deprecated: 2.628773432s, ctrlflow: 2.607891806s, printf: 2.530308214s, gosec: 2.504255488s, inspect: 2.278005159s 
... 
INFO [runner/max_from_linter] 418/468 issues from linter depguard were hidden, use --max-issues-per-linter 
INFO [runner/max_from_linter] 2/52 issues from linter funlen were hidden, use --max-issues-per-linter 
INFO [runner] Issues before processing: 3021, after processing: 198 
INFO [runner] Processors filtering stat (in/out): path_shortener: 198/198, severity-rules: 198/198, skip_files: 2768/2768, generated_file_filter: 2768/2683, sort_results: 198/198, path_absoluter: 3021/3021, filename_unadjuster: 3021/3021, fixer: 1629/1629, uniq_by_line: 1629/1625, path_prettifier: 198/198, invalid_issue: 3021/3021, path_relativity: 3021/3021, skip_dirs: 2768/2768, exclusion_rules: 2683/1672, nolint_filter: 1672/1629, diff: 1629/1629, max_per_file_from_linter: 1625/1625, source_code: 198/198, cgo: 3021/3021, exclusion_paths: 3021/2768, identifier_marker: 2683/2683, max_same_issues: 1625/618, max_from_linter: 618/198 
INFO [runner] processing took 94.450985ms with stages: exclusion_rules: 57.15378ms, nolint_filter: 26.169956ms, generated_file_filter: 3.187416ms, path_relativity: 1.880823ms, skip_dirs: 1.467807ms, exclusion_paths: 1.072741ms, source_code: 986.197µs, max_same_issues: 500.556µs, invalid_issue: 462.299µs, cgo: 328.992µs, path_absoluter: 306.383µs, uniq_by_line: 270.062µs, identifier_marker: 246.661µs, filename_unadjuster: 220.097µs, max_per_file_from_linter: 133.18µs, max_from_linter: 30.071µs, path_shortener: 28.259µs, path_prettifier: 4.348µs, diff: 519ns, fixer: 291ns, sort_results: 274ns, skip_files: 194ns, severity-rules: 79ns 
INFO [runner] linters took 7.70599729s with stages: goanalysis_metalinter: 7.611210805s 
INFO File cache stats: 104 entries of total size 584.4KiB 
INFO Memory: 87 samples, avg is 966.8MB, max is 1488.2MB 
INFO Execution took 8.5517257s                    
golangci-lint run -v > /dev/null  85,33s user 5,58s system 1051% cpu 8,646 total
v1.62.2 - golangci-lint repo - 8.35s
$ go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
go version go1.23.7 linux/amd64
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /home/ldez/sources/golangci/golangci-lint /home/ldez/sources/golangci /home/ldez/sources /home/ldez /home /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 33 linters: [bodyclose copyloopvar depguard dogsled dupl errcheck errorlint funlen gocheckcompilerdirectives gochecknoinits goconst gocritic gocyclo godox goprintffuncname gosec gosimple govet ineffassign intrange lll misspell mnd nakedret noctx nolintlint revive staticcheck testifylint unconvert unparam unused whitespace] 
INFO [loader] Go packages loading at mode 8767 (exports_file|imports|compiled_files|deps|types_sizes|files|name) took 680.835251ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 11.233699ms 
INFO [linters_context/goanalysis] analyzers took 2m45.62470055s with top 10 stages: buildir: 1m2.189828651s, the_only_name: 10.723553541s, dupl: 4.977277056s, gocritic: 3.840314293s, fact_deprecated: 3.11368792s, gosec: 2.660986493s, unconvert: 2.618248641s, buildssa: 2.521156743s, printf: 2.50766643s, inspect: 2.50169218s 
...
INFO [runner] Issues before processing: 2791, after processing: 289 
INFO [runner] Processors filtering stat (in/out): identifier_marker: 2706/2706, diff: 1608/1608, source_code: 289/289, path_prefixer: 289/289, path_prettifier: 2791/2791, skip_dirs: 2791/2791, autogenerated_exclude: 2791/2706, max_same_issues: 1608/691, severity-rules: 289/289, sort_results: 289/289, cgo: 2791/2791, invalid_issue: 2791/2791, max_per_file_from_linter: 1608/1608, max_from_linter: 691/289, path_shortener: 289/289, exclude-rules: 2706/1664, uniq_by_line: 1621/1608, exclude: 2706/2706, nolint: 1664/1621, fixer: 289/289, filename_unadjuster: 2791/2791, skip_files: 2791/2791 
INFO [runner] processing took 135.70577ms with stages: exclude-rules: 61.108053ms, nolint: 32.638312ms, identifier_marker: 30.068144ms, path_prettifier: 5.04293ms, autogenerated_exclude: 3.418218ms, source_code: 1.141112ms, skip_dirs: 1.136144ms, max_same_issues: 435.619µs, uniq_by_line: 224.4µs, cgo: 150.374µs, invalid_issue: 142.972µs, filename_unadjuster: 85.118µs, path_shortener: 45.917µs, max_from_linter: 35.36µs, max_per_file_from_linter: 31.507µs, exclude: 332ns, diff: 286ns, fixer: 278ns, skip_files: 252ns, sort_results: 186ns, severity-rules: 177ns, path_prefixer: 79ns 
INFO [runner] linters took 7.660672374s with stages: goanalysis_metalinter: 7.524871034s 
INFO File cache stats: 618 entries of total size 1.7MiB 
INFO Memory: 85 samples, avg is 1037.4MB, max is 1689.1MB 
INFO Execution took 8.356860327s                  
golangci-lint run -v > /dev/null  84,60s user 4,89s system 1059% cpu 8,446 total
v1.61.0 - golangci-lint repo - 9.05s
$ go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
go version go1.23.7 linux/amd64
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /home/ldez/sources/golangci/golangci-lint /home/ldez/sources/golangci /home/ldez/sources /home/ldez /home /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 33 linters: [bodyclose copyloopvar depguard dogsled dupl errcheck errorlint funlen gocheckcompilerdirectives gochecknoinits goconst gocritic gocyclo godox goprintffuncname gosec gosimple govet ineffassign intrange lll misspell mnd nakedret noctx nolintlint revive staticcheck testifylint unconvert unparam unused whitespace] 
INFO [loader] Go packages loading at mode 575 (compiled_files|deps|files|exports_file|imports|name|types_sizes) took 712.161217ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 24.055787ms 
INFO [linters_context/goanalysis] analyzers took 2m40.260945877s with top 10 stages: buildir: 1m8.654494206s, the_only_name: 11.707940903s, dupl: 5.242718886s, gocritic: 3.003850039s, fact_deprecated: 2.785451601s, unconvert: 2.713514812s, gosec: 2.492745967s, printf: 2.46932154s, ctrlflow: 2.257510384s, buildssa: 2.25570985s 
...
INFO [runner] Issues before processing: 2790, after processing: 286 
INFO [runner] Processors filtering stat (in/out): cgo: 2790/2790, sort_results: 286/286, identifier_marker: 2705/2705, uniq_by_line: 1618/1605, diff: 1605/1605, source_code: 286/286, path_prefixer: 286/286, severity-rules: 286/286, filename_unadjuster: 2790/2790, invalid_issue: 2790/2790, skip_dirs: 2790/2790, autogenerated_exclude: 2790/2705, exclude: 2705/2705, max_same_issues: 1605/688, max_from_linter: 688/286, path_prettifier: 2790/2790, skip_files: 2790/2790, exclude-rules: 2705/1661, nolint: 1661/1618, max_per_file_from_linter: 1605/1605, path_shortener: 286/286, fixer: 286/286 
INFO [runner] processing took 129.820957ms with stages: exclude-rules: 61.4292ms, nolint: 30.920589ms, identifier_marker: 27.118054ms, path_prettifier: 4.379625ms, autogenerated_exclude: 2.771698ms, source_code: 1.112775ms, skip_dirs: 1.034831ms, max_same_issues: 392.828µs, uniq_by_line: 205.513µs, invalid_issue: 147.712µs, cgo: 125.257µs, filename_unadjuster: 75.152µs, path_shortener: 39.429µs, max_per_file_from_linter: 34.246µs, max_from_linter: 32.699µs, exclude: 300ns, fixer: 293ns, skip_files: 217ns, sort_results: 205ns, diff: 179ns, severity-rules: 78ns, path_prefixer: 77ns 
INFO [runner] linters took 8.31836299s with stages: goanalysis_metalinter: 8.188491451s 
INFO File cache stats: 617 entries of total size 1.7MiB 
INFO Memory: 92 samples, avg is 995.7MB, max is 1544.5MB 
INFO Execution took 9.058452268s                  
golangci-lint run -v > /dev/null  91,26s user 5,56s system 1059% cpu 9,137 total

@ldez
Copy link
Member

ldez commented Mar 14, 2025

🤔 Maybe this is only on darwin/arm64 but I don't understand why.

@ldez ldez added the feedback required Requires additional feedback label Mar 14, 2025
@ldez
Copy link
Member

ldez commented Mar 14, 2025

🤔 This reminds me of another issue: #5042 (comment)

@ldez
Copy link
Member

ldez commented Mar 14, 2025

I only have Linux computers, so I cannot try locally on macOS.

But inside our CI, we run golangci-lint on macOS (arm64) and there are no problems.
It's a CI, and so we don't have the same context as a local computer (no need for codesign or other macOS tools).

I also have "isolated" benchmarks that I launch on PRs (before merging them), and I only see performance improvements since v1.61.

So, my conclusions, based only on information you provided:

  • either it's a problem with codesign or macOS tooling (my bet is on this one)
  • or it is something only related to darwin/arm64 (but I don't think so)
  • or something else 🤔

@ldez ldez added question Further information is requested platform: macos Issue that is related to MacOS and removed bug Something isn't working labels Mar 14, 2025
@pfouilloux
Copy link
Author

pfouilloux commented Mar 17, 2025

Hi @ldez 👋 Thanks for checking on this 🙏

I've run the benchmarks again using the exact same list of linters as yours and seeing similar timings...
Having a look to see if I can isolate one linter that could explain the different behaviour 🙂

This is the delta between our linter lists

'<': The ones yours has but we don't have
'>': The ones we have but yours doesn't have

<     - bodyclose
<     - copyloopvar
      - depguard
      - dogsled
<     - dupl
      - errcheck
<     - errorlint
>     - exhaustive
<     - funlen
<     - gocheckcompilerdirectives
<     - gochecknoinits
<     - goconst
>     - gci
      - gocritic
>     - gofmt
>     - goimports
<     - gocyclo
<     - godox
<     - gosec
>     - gosimple
      - govet
<     - intrange
<     - ineffassign
<     - lll
>     - makezero
<     - mnd
<     - misspell
<     - nakedret
<     - noctx
<     - nolintlint
>     - predeclared
      - revive
>     - rowserrcheck
      - staticcheck
<     - testifylint
>     - testpackage
>     - tparallel
>     - typecheck
      - unconvert
<     - unparam
      - unused
<     - whitespace
v1.61.0 - golangci-lint repo - 7.86s
go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
go version go1.24.1 darwin/arm64
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/3-resources/golangci-lint /Users/pfx/code/3-resources /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 33 linters: [bodyclose copyloopvar depguard dogsled dupl errcheck errorlint funlen gocheckcompilerdirectives gochecknoinits goconst gocritic gocyclo godox goprintffuncname gosec gosimple govet ineffassign intrange lll misspell mnd nakedret noctx revive rowserrcheck staticcheck testifylint unconvert unparam unused whitespace] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (exports_file|files|types_sizes|compiled_files|deps|imports|name) took 571.880833ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 12.676167ms 
INFO [linters_context/goanalysis] analyzers took 2m28.123184355s with top 10 stages: SA5012: 2.103526545s, SA1030: 1.550736669s, SA5009: 1.531923629s, SA1000: 1.51965754s, SA4012: 1.510868129s, nilness: 1.501980879s, SA4015: 1.403049665s, SA1025: 1.394331919s, SA1032: 1.363516459s, SA1031: 1.362193334s 
INFO [runner] Issues before processing: 37429, after processing: 187 
INFO [runner] Processors filtering stat (in/out): max_same_issues: 187/187, sort_results: 187/187, path_prettifier: 37422/37422, skip_files: 37422/37422, exclude-rules: 37422/37422, nolint: 37422/37422, uniq_by_line: 37422/187, max_per_file_from_linter: 187/187, cgo: 37429/37429, fixer: 187/187, severity-rules: 187/187, path_prefixer: 187/187, filename_unadjuster: 37429/37429, invalid_issue: 37429/37422, skip_dirs: 37422/37422, autogenerated_exclude: 37422/37422, identifier_marker: 37422/37422, source_code: 187/187, exclude: 37422/37422, diff: 187/187, max_from_linter: 187/187, path_shortener: 187/187 
INFO [runner] processing took 206.888545ms with stages: identifier_marker: 195.183084ms, path_prettifier: 7.737625ms, source_code: 818.458µs, uniq_by_line: 547.959µs, nolint: 491.376µs, skip_dirs: 446.791µs, filename_unadjuster: 358.292µs, autogenerated_exclude: 351.625µs, exclude-rules: 306.001µs, invalid_issue: 303.167µs, cgo: 294.167µs, sort_results: 35.75µs, path_shortener: 9.75µs, max_per_file_from_linter: 3.167µs, max_same_issues: 417ns, diff: 209ns, exclude: 208ns, skip_files: 167ns, fixer: 166ns, max_from_linter: 124ns, severity-rules: 42ns, path_prefixer: 0s 
INFO [runner] linters took 6.880710417s with stages: goanalysis_metalinter: 6.673732709s 
INFO File cache stats: 54 entries of total size 269.1KiB 
INFO Memory: 76 samples, avg is 1616.5MB, max is 2155.1MB 
INFO Execution took 7.472417042s                  

________________________________________________________
Executed in    7.56 secs    fish           external
   usr time   18.93 secs   31.00 micros   18.93 secs
   sys time    6.02 secs  319.00 micros    6.02 secs
v1.64.7 - golangci-lint repo - 7.28s
❯ go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
go version go1.24.1 darwin/arm64
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/3-resources/golangci-lint /Users/pfx/code/3-resources /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [goenv] Read go env for 5.3755ms: map[string]string{"GOCACHE":"/Users/pfx/Library/Caches/go-build", "GOROOT":"/Users/pfx/.local/share/mise/installs/go/1.24.1"} 
INFO [lintersdb] Active 33 linters: [bodyclose copyloopvar depguard dogsled dupl errcheck errorlint funlen gocheckcompilerdirectives gochecknoinits goconst gocritic gocyclo godox goprintffuncname gosec gosimple govet ineffassign intrange lll misspell mnd nakedret noctx revive rowserrcheck staticcheck testifylint unconvert unparam unused whitespace] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (compiled_files|deps|exports_file|imports|name|files|types_sizes) took 580.272792ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 11.058792ms 
INFO [linters_context/goanalysis] analyzers took 1m39.363379372s with top 10 stages: buildir: 39.807083522s, the_only_name: 9.053051338s, dupl: 3.436968168s, fact_deprecated: 2.749493698s, unconvert: 2.718351003s, printf: 2.310162425s, inspect: 2.148501363s, ctrlflow: 1.782389607s, gosec: 1.575501238s, fact_purity: 1.339504269s 
INFO [runner/exclusion_rules] Skipped 0 issues by rules: [Source: "(?i)^//\\$\\(which go\\)", Linters: "gocritic"] 
INFO [runner] Issues before processing: 1537, after processing: 376 
INFO [runner] Processors filtering stat (in/out): filename_unadjuster: 1537/1537, exclusion_paths: 1537/1537, skip_files: 1537/1537, max_per_file_from_linter: 376/376, path_shortener: 376/376, severity-rules: 376/376, path_prettifier: 376/376, path_absoluter: 1537/1537, skip_dirs: 1537/1537, identifier_marker: 1452/1452, exclusion_rules: 1452/410, uniq_by_line: 386/376, source_code: 376/376, invalid_issue: 1537/1537, path_relativity: 1537/1537, generated_file_filter: 1537/1452, diff: 386/386, fixer: 386/386, max_same_issues: 376/376, sort_results: 376/376, cgo: 1537/1537, nolint_filter: 410/386, max_from_linter: 376/376 
INFO [runner] processing took 30.761003ms with stages: nolint_filter: 14.384541ms, exclusion_rules: 7.325917ms, generated_file_filter: 4.785708ms, source_code: 1.779625ms, skip_dirs: 837.043µs, sort_results: 747.417µs, path_relativity: 476.959µs, path_absoluter: 75.749µs, invalid_issue: 74.792µs, identifier_marker: 72.709µs, cgo: 62.375µs, uniq_by_line: 46.709µs, path_shortener: 41.167µs, filename_unadjuster: 29.083µs, max_per_file_from_linter: 10.292µs, path_prettifier: 8.875µs, max_same_issues: 626ns, exclusion_paths: 458ns, fixer: 251ns, diff: 250ns, max_from_linter: 208ns, severity-rules: 166ns, skip_files: 83ns 
INFO [runner] linters took 7.1824815s with stages: goanalysis_metalinter: 7.151627833s 
INFO File cache stats: 131 entries of total size 755.6KiB 
INFO Memory: 79 samples, avg is 859.8MB, max is 1338.8MB 
INFO Execution took 7.7811525s                    

________________________________________________________
Executed in    7.86 secs    fish           external
   usr time   44.03 secs   42.00 micros   44.03 secs
   sys time   17.63 secs  344.00 micros   17.63 secs

@pfouilloux

This comment has been minimized.

@ldez

This comment has been minimized.

@ldez
Copy link
Member

ldez commented Mar 17, 2025

I take your configuration, go1.23.7, and I run all the linters you are using:

#!/bin/zsh -e

linters=(
  "dogsled"
  "errcheck"
  "exhaustive"
  "gci"
  "gocritic"
  "gofmt"
  "goimports"
  "revive"
  "goprintffuncname"
  "gosimple"
  "govet"
  "makezero"
  "predeclared"
  "staticcheck"
  "testpackage"
  "tparallel"
  "unconvert"
  "depguard"
  "unused"
  "rowserrcheck"
)

echo 'name,real,user,sys'

for item in "${linters[@]}"
do
  golangci-lint cache clean
  printf "$item,"
  { /usr/bin/time -q -f"%e,%U,%S" golangci-lint run --issues-exit-code=0 --print-issued-lines=false --enable-only $item > /dev/null; } 2>&1
done
v1.61
name real user sys
dogsled 0.77 1.22 0.51
errcheck 0.97 2.51 0.81
exhaustive 2.61 14.94 1.55
gci 0.84 1.56 0.58
gocritic 1.31 4.20 0.86
gofmt 0.86 1.50 0.56
goimports 0.88 1.68 0.55
revive 1.50 6.76 3.67
goprintffuncname 0.78 1.24 0.51
gosimple 8.56 79.60 2.86
govet 2.27 13.07 1.51
makezero 1.04 2.69 0.84
predeclared 0.75 1.19 0.52
staticcheck 9.26 83.20 3.21
testpackage 0.88 1.33 0.58
tparallel 1.05 3.00 0.87
unconvert 1.12 2.65 0.86
depguard 0.77 1.20 0.51
unused 1.04 2.82 0.75
rowserrcheck 1.05 2.97 0.90
v1.62
name real user sys
dogsled 0.87 1.32 0.59
errcheck 1.10 2.65 0.90
exhaustive 2.51 14.20 1.47
gci 0.87 1.67 0.59
gocritic 1.46 4.39 0.95
gofmt 0.82 1.44 0.58
goimports 1.00 2.14 1.33
revive 1.51 6.74 3.71
goprintffuncname 0.76 1.21 0.51
gosimple 8.67 81.41 3.12
govet 2.32 12.79 1.47
makezero 0.98 2.51 0.78
predeclared 0.75 1.21 0.50
staticcheck 13.11 89.02 3.54
testpackage 1.31 1.56 0.84
tparallel 1.28 3.07 0.95
unconvert 1.01 2.64 0.83
depguard 0.75 1.17 0.50
unused 1.07 2.81 0.79
rowserrcheck 1.05 2.87 0.80
v1.64
name real user sys
dogsled 0.76 1.18 0.52
errcheck 1.00 2.65 0.89
exhaustive 2.25 13.00 1.22
gci 1.00 1.71 0.63
gocritic 1.64 4.53 1.07
gofmt 0.86 1.51 0.57
goimports 1.03 2.23 1.42
revive 1.54 6.40 3.84
goprintffuncname 0.77 1.27 0.51
gosimple 8.51 72.92 2.58
govet 2.38 12.03 1.29
makezero 0.97 2.59 0.82
predeclared 0.77 1.21 0.55
staticcheck 8.33 73.64 2.67
testpackage 0.88 1.41 0.56
tparallel 1.22 3.07 0.99
unconvert 1.19 2.86 0.93
depguard 0.85 1.35 0.58
unused 1.03 2.77 0.83
rowserrcheck 1.08 2.87 0.90

And I don't detect any significant performance changes between v1.61, v1.62, and v1.64.

@pfouilloux
Copy link
Author

pfouilloux commented Mar 17, 2025

Certainly, sorry for the confusion 🙂
Switched to master and removed v2 from the config.

git log
commit 7bcf51e684a1fae1ff72b6f74f6451bc11d67ce7 (HEAD -> master, origin/master)
Author: GolangCI-Lint Releaser <[email protected]>
Date:   Wed Mar 12 01:11:37 2025 +0100
    docs: update documentation assets (#5527)
    
    Co-authored-by: Fernandez Ludovic <[email protected]>

I've run these latest on my linux machine and I can reproduce same results as you, which is interesting 🤔 To crosscheck I tried it on the https://github.com/wailsapp/wails project and I'm seeing a rather large performance difference there even on linux. Still fast because my machine is quite performant but 7s difference would be much more on a slower machine. Note that with the main branch of golangci-lint repo I'm seeing the performance difference as well.

I wish I could just share our source but due to NDAs and whatnot that's not an option at this time sorry 😓

Unfortunately I'm running a bit late for an appointment so I won't be able to run any further tests for a bit but I'm planning to rerun the minimal tests on both my mac and linux desktops either later today or tomorrow.

EndeavourOS 6.13.7-arch1-1 (64bit) / AMD Ryzen 9 5900X 12-Core / 32 GB ram

Test A - Full config file for our repo

Config file
run:
  allow-parallel-runners: true
  build-tags:
    - integration
  timeout: 5m

output:
  sort-results: true

linters:
  disable-all: true
  enable:
    - dogsled
    - errcheck
    - exhaustive
    - gci
    - gocritic
    - gofmt
    - goimports
    - revive
    - goprintffuncname
    - gosimple
    - govet
    - makezero
    - predeclared
    - staticcheck
    - testpackage
    - tparallel
    - typecheck
    - unconvert
    - depguard
    - unused
    - rowserrcheck

linters-settings:
  rowserrcheck:
    packages:
      - github.com/jackc/pgx/v5
  errcheck:
    check-blank: false # Will be enabled in a follow-up commit
  depguard:
    rules:
      main:
        list-mode: lax
        files:
          - "**/handler/**/main.go"
        allow:
          - $gostd
        deny:
          - pkg: "github.com/aws/aws-lambda-go/lambda"
            desc: The usage of this package here is probably a mistake. If you're trying to call lambda.start change it to modules/defaults.start instead (check out other handlers for a complete example). If this is a false positive, please tweak this rule on .golangci.yml

issues:
  max-issues-per-linter: 0
  max-same-issues: 0
  exclude-rules:
    - source: "^//\\$\\(which go\\)"
      linters:
        - gocritic

Golangci-lint master branch

v1.61.0 - golangci-lint repo - 9.81s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /mnt/data/2-code/1-projects/golangci-lint /mnt/data/2-code/1-projects /mnt/data/2-code /mnt/data /mnt / /home/pfx-eos] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (compiled_files|exports_file|imports|name|deps|files|types_sizes) took 352.40216ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 26.782947ms 
INFO [linters_context/goanalysis] analyzers took 13m1.20680716s with top 10 stages: SA5012: 9.650093131s, typedness: 7.339120699s, fact_purity: 7.330499127s, ctrlflow: 7.154127792s, printf: 6.568597527s, SA2003: 6.373726605s, SA1007: 6.351758861s, SA1030: 6.348868053s, SA9003: 6.295749438s, SA1025: 6.228930886s 
INFO [runner] Issues before processing: 31810, after processing: 169 
INFO [runner] Processors filtering stat (in/out): severity-rules: 169/169, skip_dirs: 31806/31806, max_per_file_from_linter: 169/169, max_same_issues: 169/169, nolint: 31806/31806, source_code: 169/169, path_shortener: 169/169, filename_unadjuster: 31810/31810, identifier_marker: 31806/31806, exclude-rules: 31806/31806, path_prefixer: 169/169, sort_results: 169/169, invalid_issue: 31810/31806, skip_files: 31806/31806, autogenerated_exclude: 31806/31806, uniq_by_line: 31806/169, diff: 169/169, max_from_linter: 169/169, fixer: 169/169, cgo: 31810/31810, path_prettifier: 31806/31806, exclude: 31806/31806 
INFO [runner] processing took 321.316547ms with stages: identifier_marker: 302.483518ms, path_prettifier: 9.588393ms, uniq_by_line: 1.97752ms, exclude-rules: 1.666524ms, nolint: 1.102062ms, filename_unadjuster: 943.369µs, cgo: 938.099µs, invalid_issue: 714.064µs, source_code: 654.043µs, autogenerated_exclude: 583.292µs, skip_dirs: 575.881µs, sort_results: 63.472µs, path_shortener: 17.94µs, max_per_file_from_linter: 6.23µs, max_same_issues: 570ns, exclude: 330ns, diff: 330ns, max_from_linter: 280ns, skip_files: 220ns, fixer: 220ns, severity-rules: 120ns, path_prefixer: 70ns 
INFO [runner] linters took 9.327558333s with stages: goanalysis_metalinter: 9.006142135s 
INFO File cache stats: 43 entries of total size 240.1KiB 
INFO Memory: 99 samples, avg is 1786.5MB, max is 2332.7MB 
INFO Execution took 9.711362571s                  
________________________________________________________
Executed in    9.81 secs    fish           external
   usr time   54.18 secs    0.00 micros   54.18 secs
   sys time    6.20 secs  858.00 micros    6.20 secs
v1.64.7 - golangci-lint repo - 7.78s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /mnt/data/2-code/1-projects/golangci-lint /mnt/data/2-code/1-projects /mnt/data/2-code /mnt/data /mnt / /home/pfx-eos] 
INFO [config_reader] Used config file .golangci.yml 
INFO [goenv] Read go env for 2.277145ms: map[string]string{"GOCACHE":"/home/pfx-eos/.cache/go-build", "GOROOT":"/home/pfx-eos/.local/share/mise/installs/go/1.24.1"} 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (deps|imports|name|types_sizes|compiled_files|exports_file|files) took 665.925471ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 12.573508ms 
INFO [linters_context/goanalysis] analyzers took 3m23.83162275s with top 10 stages: buildir: 1m10.432524578s, the_only_name: 11.413450593s, goimports: 7.066094174s, exhaustive: 5.033877808s, gocritic: 4.235239249s, fact_deprecated: 3.924781171s, inspect: 3.516950789s, unconvert: 2.977860355s, printf: 2.814915011s, ctrlflow: 2.70016179s 
INFO [runner/exclusion_rules] Skipped 0 issues by rules: [Source: "(?i)^//\\$\\(which go\\)", Linters: "gocritic"] 
INFO [runner] Issues before processing: 1559, after processing: 514 
INFO [runner] Processors filtering stat (in/out): cgo: 1559/1559, filename_unadjuster: 1559/1559, generated_file_filter: 1559/1559, fixer: 719/719, path_relativity: 1559/1559, skip_dirs: 1559/1559, identifier_marker: 1559/1559, max_same_issues: 514/514, max_from_linter: 514/514, path_shortener: 514/514, path_absoluter: 1559/1559, invalid_issue: 1559/1559, exclusion_rules: 1559/724, uniq_by_line: 719/709, severity-rules: 514/514, path_prettifier: 514/514, sort_results: 514/514, exclusion_paths: 1559/1559, skip_files: 1559/1559, nolint_filter: 724/719, diff: 719/719, max_per_file_from_linter: 709/514, source_code: 514/514 
INFO [runner] processing took 44.907968ms with stages: nolint_filter: 22.442873ms, exclusion_rules: 11.403936ms, generated_file_filter: 4.441098ms, source_code: 3.348656ms, skip_dirs: 1.261165ms, path_relativity: 742.874µs, sort_results: 600.261µs, uniq_by_line: 107.383µs, invalid_issue: 105.532µs, cgo: 101.172µs, path_absoluter: 83.822µs, max_per_file_from_linter: 79.361µs, identifier_marker: 73.322µs, path_shortener: 54.561µs, filename_unadjuster: 45.631µs, path_prettifier: 13.561µs, max_same_issues: 710ns, fixer: 610ns, exclusion_paths: 530ns, diff: 320ns, skip_files: 270ns, max_from_linter: 230ns, severity-rules: 90ns 
INFO [runner] linters took 6.971897397s with stages: goanalysis_metalinter: 6.926907607s 
INFO File cache stats: 360 entries of total size 744.7KiB 
INFO Memory: 78 samples, avg is 1089.0MB, max is 1841.1MB 
INFO Execution took 7.658412834s                  
________________________________________________________
Executed in    7.78 secs    fish           external
   usr time  102.52 secs    0.00 micros  102.52 secs
   sys time   14.73 secs  843.00 micros   14.73 secs

Wails repo master branch

Note: run from the v2 subdirectory

v1.61.0 - wails repo - 2.30s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v  > /dev/null
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /mnt/data/2-code/1-projects/wails/v2 /mnt/data/2-code/1-projects/wails /mnt/data/2-code/1-projects /mnt/data/2-code /mnt/data /mnt / /home/pfx-eos] 
INFO [config_reader] Used config file .golangci.yml 
WARN [config_reader] The configuration option `output.format` is deprecated, please use `output.formats` 
WARN [config_reader] The configuration option `linters.errcheck.ignore` is deprecated, please use `linters.errcheck.exclude-functions`. 
WARN [lintersdb] The linter "deadcode" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "exhaustivestruct" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "golint" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "ifshort" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "interfacer" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "maligned" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "nosnakecase" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "scopelint" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "structcheck" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "varcheck" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The name "goerr113" is deprecated. The linter has been renamed to: err113. 
INFO [lintersdb] Active 18 linters: [canonicalheader copyloopvar errcheck errname fatcontext gochecksumtype gofmt gofumpt gosimple inamedparam intrange misspell mnd perfsprint protogetter sloglint spancheck testifylint] 
INFO [loader] Go packages loading at mode 575 (imports|name|types_sizes|compiled_files|deps|exports_file|files) took 354.185119ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 6.964703ms 
WARN [linters_context] copyloopvar: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [linters_context/goanalysis] analyzers took 1.13083738s with top 10 stages: fact_purity: 86.218365ms, S1029: 81.68017ms, S1034: 63.105259ms, ctrlflow: 62.352643ms, S1011: 54.50111ms, spancheck: 54.425416ms, S1002: 44.221302ms, S1016: 32.272319ms, buildir: 30.074658ms, S1028: 29.011443ms 
WARN [linters_context] intrange: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [runner/max_same_issues] 25/28 issues with text "missing type in composite literal" were hidden, use --max-same-issues 
INFO [runner/max_same_issues] 3/6 issues with text "undefined: ansi" were hidden, use --max-same-issues 
INFO [runner/max_same_issues] 3/6 issues with text "undefined: dbus" were hidden, use --max-same-issues 
INFO [runner] Issues before processing: 2862, after processing: 21 
INFO [runner] Processors filtering stat (in/out): max_from_linter: 21/21, skip_dirs: 2860/2860, identifier_marker: 2860/2860, exclude-rules: 2860/2860, uniq_by_line: 2860/52, max_per_file_from_linter: 52/52, source_code: 21/21, path_prefixer: 21/21, sort_results: 21/21, cgo: 2862/2862, filename_unadjuster: 2862/2862, invalid_issue: 2862/2860, autogenerated_exclude: 2860/2860, path_prettifier: 2860/2860, skip_files: 2860/2860, max_same_issues: 52/21, severity-rules: 21/21, fixer: 21/21, exclude: 2860/2860, nolint: 2860/2860, diff: 52/52, path_shortener: 21/21 
INFO [runner] processing took 26.683842ms with stages: identifier_marker: 24.943827ms, path_prettifier: 999.015µs, source_code: 188.823µs, uniq_by_line: 88.411µs, nolint: 69.341µs, exclude-rules: 69.061µs, invalid_issue: 61.011µs, cgo: 59.981µs, filename_unadjuster: 59.911µs, skip_dirs: 51.71µs, autogenerated_exclude: 50.391µs, max_same_issues: 27.9µs, sort_results: 5.64µs, path_shortener: 3.52µs, max_per_file_from_linter: 2.23µs, max_from_linter: 1.97µs, fixer: 320ns, skip_files: 260ns, exclude: 260ns, diff: 110ns, path_prefixer: 80ns, severity-rules: 70ns 
INFO [runner] linters took 1.869006049s with stages: goanalysis_metalinter: 1.842253166s, copyloopvar: 9.65µs, intrange: 8.15µs 
INFO File cache stats: 22 entries of total size 71.5KiB 
INFO Memory: 24 samples, avg is 283.6MB, max is 491.9MB 
INFO Execution took 2.234271641s                  
________________________________________________________
Executed in    2.30 secs    fish           external
   usr time    5.82 secs    0.00 micros    5.82 secs
   sys time    0.66 secs  896.00 micros    0.66 secs
v1.64.7 - wails repo - 9.76s
golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v  > /dev/null
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /mnt/data/2-code/1-projects/wails/v2 /mnt/data/2-code/1-projects/wails /mnt/data/2-code/1-projects /mnt/data/2-code /mnt/data /mnt / /home/pfx-eos] 
INFO [config_reader] Used config file .golangci.yml 
WARN [config_reader] The configuration option `output.uniq-by-line` is deprecated, please use `issues.uniq-by-line` 
WARN [config_reader] The configuration option `output.format` is deprecated, please use `output.formats` 
WARN [config_reader] The configuration option `linters.errcheck.ignore` is deprecated, please use `linters.errcheck.exclude-functions`. 
WARN [lintersdb] The linter "deadcode" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "execinquery" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "exhaustivestruct" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "exportloopref" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "golint" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "gomnd" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "ifshort" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "interfacer" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "maligned" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "nosnakecase" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "scopelint" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "structcheck" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The linter "varcheck" is deprecated (step 2) and deactivated. It should be removed from the list of disabled linters. https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle 
WARN [lintersdb] The name "goerr113" is deprecated. The linter has been renamed to: err113. 
INFO [goenv] Read go env for 2.393183ms: map[string]string{"GOCACHE":"/home/pfx-eos/.cache/go-build", "GOROOT":"/home/pfx-eos/.local/share/mise/installs/go/1.24.1"} 
INFO [lintersdb] Active 23 linters: [canonicalheader copyloopvar errcheck errname exptostd fatcontext gochecksumtype gofmt gofumpt gosimple iface inamedparam intrange misspell mnd nilnesserr perfsprint protogetter recvcheck sloglint spancheck testifylint usetesting] 
INFO [loader] Go packages loading at mode 8767 (imports|exports_file|name|types_sizes|compiled_files|deps|files) took 4.730382958s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 5.482387ms 
WARN [linters_context] copyloopvar: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [linters_context/goanalysis] analyzers took 16.224977482s with top 10 stages: buildir: 12.796859379s, inspect: 933.578762ms, ctrlflow: 337.003024ms, buildssa: 275.044075ms, gofumpt: 212.649143ms, fact_purity: 204.41011ms, gofmt: 146.222048ms, errcheck: 141.314263ms, misspell: 132.165664ms, isgenerated: 123.888557ms 
WARN [linters_context] intrange: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [runner] Issues before processing: 444, after processing: 4 
INFO [runner] Processors filtering stat (in/out): skip_dirs: 252/252, identifier_marker: 252/252, source_code: 4/4, cgo: 444/444, path_relativity: 252/252, exclusion_paths: 252/252, generated_file_filter: 252/252, fixer: 252/252, max_per_file_from_linter: 4/4, max_from_linter: 4/4, severity-rules: 4/4, skip_files: 252/252, exclusion_rules: 252/252, nolint_filter: 252/252, diff: 252/252, max_same_issues: 4/4, path_shortener: 4/4, path_prettifier: 4/4, sort_results: 4/4, path_absoluter: 444/444, filename_unadjuster: 444/444, invalid_issue: 444/252, uniq_by_line: 252/4 
INFO [runner] processing took 326.294µs with stages: path_relativity: 118.812µs, source_code: 67.441µs, cgo: 47.561µs, path_absoluter: 13.38µs, filename_unadjuster: 13.2µs, uniq_by_line: 12.14µs, invalid_issue: 9.33µs, nolint_filter: 9.08µs, identifier_marker: 8.14µs, generated_file_filter: 6.32µs, skip_dirs: 6.22µs, exclusion_rules: 6.1µs, max_same_issues: 2.35µs, sort_results: 1.61µs, path_shortener: 1.59µs, max_from_linter: 710ns, max_per_file_from_linter: 530ns, exclusion_paths: 480ns, fixer: 350ns, path_prettifier: 270ns, skip_files: 260ns, diff: 260ns, severity-rules: 160ns 
INFO [runner] linters took 4.931479362s with stages: goanalysis_metalinter: 4.931072676s, intrange: 9.58µs, copyloopvar: 9.1µs 
INFO File cache stats: 4 entries of total size 17.3KiB 
INFO Memory: 98 samples, avg is 284.6MB, max is 643.5MB 
INFO Execution took 9.670547992s                  
________________________________________________________
Executed in    9.76 secs    fish           external
   usr time   61.51 secs    0.00 micros   61.51 secs
   sys time    5.95 secs  862.00 micros    5.95 secs

@ldez
Copy link
Member

ldez commented Mar 17, 2025

Are you using cgo?

@pfouilloux
Copy link
Author

Are you using cgo?

No. I haven't checked Wails, I think they might though... But I'm confident our project doesn't: our build command starts with CGO_ENABLED=0.

@ldez
Copy link
Member

ldez commented Mar 17, 2025

Benchmarks against wails/v2.

Note: wails uses enable-all and each new version of golangci-lint has new linters activated and existing linters are updated.

v1.64
name real user sys
canonicalheader 0.51 1.00 0.32
copyloopvar 0.40 0.56 0.17
errcheck 0.46 1.00 0.32
errname 0.48 1.03 0.30
fatcontext 0.50 1.13 0.30
gochecksumtype 0.52 1.09 0.35
gofmt 0.42 0.57 0.21
gofumpt 0.41 0.60 0.17
gosimple 5.41 18.96 0.70
inamedparam 0.40 0.54 0.21
intrange 0.42 0.61 0.20
misspell 0.42 0.59 0.21
mnd 0.40 0.52 0.20
perfsprint 0.49 1.03 0.30
protogetter 0.50 1.09 0.30
sloglint 0.48 1.00 0.30
spancheck 1.71 5.01 0.43
testifylint 0.45 0.97 0.30
$ golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null                  
golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z
INFO [config_reader] Config search paths: [./ /home/ldez/sources/experimental/wails/v2 /home/ldez/sources/experimental/wails /home/ldez/sources/experimental /home/ldez/sources /home/ldez /home /]
INFO [config_reader] Used config file .golangci.yml

INFO [goenv] Read go env for 2.298485ms: map[string]string{"GOCACHE":"/home/ldez/.cache/go-build", "GOROOT":"/home/ldez/.gvm/gos/go1.24.1"}
INFO [lintersdb] Active 23 linters: [canonicalheader copyloopvar errcheck errname exptostd fatcontext gochecksumtype gofmt gofumpt gosimple iface inamedparam intrange misspell mnd nilnesserr perfsprint protogetter recvcheck sloglint spancheck testifylint usetesting]
INFO [loader] Go packages loading at mode 8767 (types_sizes|exports_file|compiled_files|deps|files|imports|name) took 285.92251ms
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 7.01559ms
INFO [linters_context/goanalysis] analyzers took 18.279414045s with top 10 stages: buildir: 15.060461223s, inspect: 875.681635ms, ctrlflow: 395.50644ms, fact_purity: 285.255152ms, gofumpt: 186.557715ms, buildssa: 173.486061ms, gofmt: 154.314537ms, misspell: 129.042251ms, isgenerated: 105.675439ms, spancheck: 85.706278ms
INFO [runner] Issues before processing: 444, after processing: 4
INFO [runner] Processors filtering stat (in/out): uniq_by_line: 252/4, max_per_file_from_linter: 4/4, severity-rules: 4/4, fixer: 252/252, path_absoluter: 444/444, cgo: 444/444, invalid_issue: 444/252, path_relativity: 252/252, skip_files: 252/252, identifier_marker: 252/252, max_same_issues: 4/4, filename_unadjuster: 444/444, skip_dirs: 252/252, generated_file_filter: 252/252, exclusion_rules: 252/252, diff: 252/252, max_from_linter: 4/4, source_code: 4/4, path_shortener: 4/4, exclusion_paths: 252/252, nolint_filter: 252/252, path_prettifier: 4/4, sort_results: 4/4
INFO [runner] processing took 316.797µs with stages: path_relativity: 153.073µs, source_code: 65.19µs, cgo: 13.199µs, path_absoluter: 12.783µs, uniq_by_line: 11.151µs, filename_unadjuster: 9.893µs, nolint_filter: 8.458µs, identifier_marker: 7.052µs, invalid_issue: 7.005µs, skip_dirs: 6.027µs, generated_file_filter: 5.56µs, exclusion_rules: 5.486µs, max_same_issues: 3.659µs, path_shortener: 2.069µs, sort_results: 1.938µs, max_from_linter: 1.666µs, exclusion_paths: 505ns, diff: 477ns, fixer: 454ns, max_per_file_from_linter: 446ns, skip_files: 335ns, path_prettifier: 210ns, severity-rules: 161ns
INFO [runner] linters took 5.656799217s with stages: goanalysis_metalinter: 5.656401645s, copyloopvar: 6.864µs, intrange: 6.723µs
INFO File cache stats: 4 entries of total size 17.3KiB
INFO Memory: 61 samples, avg is 489.3MB, max is 679.5MB
INFO Execution took 5.952928014s                  
golangci-lint run -v > /dev/null  21,13s user 0,82s system 361% cpu 6,077 total
v1.62
name real user sys
canonicalheader 0.50 1.07 0.30
copyloopvar 0.39 0.53 0.18
errcheck 0.49 1.07 0.31
errname 0.50 1.12 0.31
fatcontext 0.52 1.13 0.31
gochecksumtype 0.48 1.01 0.31
gofmt 0.37 0.53 0.19
gofumpt 0.39 0.59 0.16
gosimple 5.74 19.85 0.82
inamedparam 0.40 0.55 0.20
intrange 0.42 0.61 0.18
misspell 0.40 0.58 0.15
mnd 0.37 0.53 0.15
perfsprint 0.48 1.03 0.31
protogetter 0.49 1.08 0.28
sloglint 0.47 1.01 0.29
spancheck 1.93 5.71 0.51
testifylint 0.49 1.03 0.33
$  golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO [config_reader] Config search paths: [./ /home/ldez/sources/experimental/wails/v2 /home/ldez/sources/experimental/wails /home/ldez/sources/experimental /home/ldez/sources /home/ldez /home /]
INFO [config_reader] Used config file .golangci.yml

INFO [lintersdb] Active 20 linters: [canonicalheader copyloopvar errcheck errname fatcontext gochecksumtype gofmt gofumpt gosimple iface inamedparam intrange misspell mnd perfsprint protogetter recvcheck sloglint spancheck testifylint]
INFO [loader] Go packages loading at mode 8767 (files|imports|types_sizes|compiled_files|deps|exports_file|name) took 274.549479ms
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 8.949504ms
INFO [linters_context/goanalysis] analyzers took 16.344960567s with top 10 stages: buildir: 14.070149097s, inspect: 806.191607ms, ctrlflow: 357.441031ms, fact_purity: 251.172924ms, gofumpt: 180.013262ms, gofmt: 101.359885ms, misspell: 73.054634ms, protogetter: 62.596813ms, S1036: 43.046842ms, isgenerated: 42.49562ms
INFO [runner/max_same_issues] 25/28 issues with text "missing type in composite literal" were hidden, use --max-same-issues
INFO [runner] Issues before processing: 2182, after processing: 15
INFO [runner] Processors filtering stat (in/out): fixer: 15/15, sort_results: 15/15, skip_dirs: 2045/2045, max_from_linter: 15/15, source_code: 15/15, severity-rules: 15/15, nolint: 2045/2045, path_shortener: 15/15, path_prettifier: 2045/2045, autogenerated_exclude: 2045/2045, identifier_marker: 2045/2045, exclude: 2045/2045, filename_unadjuster: 2182/2182, exclude-rules: 2045/2045, diff: 40/40, path_prefixer: 15/15, max_per_file_from_linter: 40/40, max_same_issues: 40/15, cgo: 2182/2182, invalid_issue: 2182/2045, skip_files: 2045/2045, uniq_by_line: 2045/40
INFO [runner] processing took 21.28431ms with stages: identifier_marker: 19.902054ms, path_prettifier: 789.713µs, source_code: 158.6µs, nolint: 57.714µs, uniq_by_line: 56.266µs, cgo: 53.746µs, exclude-rules: 50.891µs, filename_unadjuster: 44.975µs, invalid_issue: 44.1µs, skip_dirs: 41.471µs, autogenerated_exclude: 36.884µs, max_same_issues: 30.64µs, sort_results: 8.171µs, path_shortener: 3.562µs, max_per_file_from_linter: 2.183µs, max_from_linter: 1.957µs, fixer: 374ns, exclude: 318ns, skip_files: 278ns, diff: 178ns, severity-rules: 150ns, path_prefixer: 85ns
INFO [runner] linters took 5.446111641s with stages: goanalysis_metalinter: 5.424725416s, copyloopvar: 8.119µs, intrange: 7.858µs
INFO File cache stats: 159 entries of total size 371.1KiB
INFO Memory: 59 samples, avg is 569.0MB, max is 776.0MB
INFO Execution took 5.733100078s                  
golangci-lint run -v > /dev/null  19,98s user 0,96s system 359% cpu 5,820 total
v1.61
name real user sys
canonicalheader 1.65 4.84 0.45
copyloopvar 0.42 0.56 0.18
errcheck 1.69 4.95 0.46
errname 1.62 4.66 0.47
fatcontext 1.68 4.87 0.47
gochecksumtype 1.80 5.32 0.49
gofmt 0.41 0.56 0.19
gofumpt 0.43 0.62 0.18
gosimple 2.17 5.58 0.49
inamedparam 0.37 0.46 0.22
intrange 0.39 0.52 0.19
misspell 0.38 0.50 0.17
mnd 0.39 0.53 0.15
perfsprint 1.65 4.71 0.48
protogetter 1.58 4.64 0.46
sloglint 1.67 4.91 0.44
spancheck 1.84 5.44 0.45
testifylint 1.83 5.40 0.45
$ golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v > /dev/null
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO [config_reader] Config search paths: [./ /home/ldez/sources/experimental/wails/v2 /home/ldez/sources/experimental/wails /home/ldez/sources/experimental /home/ldez/sources /home/ldez /home /]
INFO [config_reader] Used config file .golangci.yml

INFO [lintersdb] Active 18 linters: [canonicalheader copyloopvar errcheck errname fatcontext gochecksumtype gofmt gofumpt gosimple inamedparam intrange misspell mnd perfsprint protogetter sloglint spancheck testifylint]
INFO [loader] Go packages loading at mode 575 (imports|name|types_sizes|deps|files|compiled_files|exports_file) took 335.050119ms
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 6.19742ms
INFO [linters_context/goanalysis] analyzers took 1.04080812s with top 10 stages: spancheck: 92.208589ms, ctrlflow: 63.664509ms, S1011: 61.154339ms, S1002: 45.960622ms, fact_purity: 45.30786ms, S1024: 43.668298ms, buildir: 38.893892ms, S1023: 30.077131ms, S1007: 27.787597ms, S1019: 27.764828ms
INFO [runner/max_same_issues] 25/28 issues with text "missing type in composite literal" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 3/6 issues with text "undefined: ansi" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 3/6 issues with text "undefined: dbus" were hidden, use --max-same-issues
INFO [runner] Issues before processing: 2862, after processing: 21
INFO [runner] Processors filtering stat (in/out): severity-rules: 21/21, fixer: 21/21, exclude: 2860/2860, uniq_by_line: 2860/52, diff: 52/52, max_same_issues: 52/21, sort_results: 21/21, filename_unadjuster: 2862/2862, invalid_issue: 2862/2860, autogenerated_exclude: 2860/2860, path_prefixer: 21/21, identifier_marker: 2860/2860, exclude-rules: 2860/2860, nolint: 2860/2860, max_per_file_from_linter: 52/52, cgo: 2862/2862, path_prettifier: 2860/2860, skip_files: 2860/2860, skip_dirs: 2860/2860, max_from_linter: 21/21, path_shortener: 21/21, source_code: 21/21
INFO [runner] processing took 25.888229ms with stages: identifier_marker: 23.902118ms, path_prettifier: 1.181857ms, source_code: 190.55µs, uniq_by_line: 83.506µs, cgo: 82.505µs, exclude-rules: 76.112µs, nolint: 72.974µs, filename_unadjuster: 65.747µs, invalid_issue: 61.314µs, skip_dirs: 59.036µs, autogenerated_exclude: 50.767µs, max_same_issues: 41.552µs, sort_results: 10.023µs, path_shortener: 4.712µs, max_per_file_from_linter: 2.381µs, max_from_linter: 1.704µs, exclude: 488ns, fixer: 326ns, diff: 212ns, skip_files: 192ns, path_prefixer: 87ns, severity-rules: 66ns
INFO [runner] linters took 2.25375911s with stages: goanalysis_metalinter: 2.227778128s, copyloopvar: 12.261µs, intrange: 9.106µs
INFO File cache stats: 22 entries of total size 71.5KiB
INFO Memory: 28 samples, avg is 268.1MB, max is 500.9MB
INFO Execution took 2.607375457s                  
golangci-lint run -v > /dev/null  7,04s user 0,84s system 290% cpu 2,709 total

@ldez
Copy link
Member

ldez commented Mar 17, 2025

In fact, wails uses cgo with specific C dependencies, but either you or me, we have the right dependencies, typecheck errors happen, and so those benchmarks are not significant.

> /dev/null was hiding the errors.

Funnily, the benchmarks prove that the linters that don't depend on types, when run alone, are faster since v1.62.

$ golangci-lint run -v
INFO golangci-lint has version 1.64.7 built with go1.24.1 from 8cffdb7d on 2025-03-11T23:26:51Z 
INFO [config_reader] Config search paths: [./ /home/ldez/sources/experimental/wails/v2 /home/ldez/sources/experimental/wails /home/ldez/sources/experimental /home/ldez/sources /home/ldez /home /] 
INFO [config_reader] Used config file .golangci.yml 
...
WARN [lintersdb] The name "goerr113" is deprecated. The linter has been renamed to: err113. 
INFO [goenv] Read go env for 2.421435ms: map[string]string{"GOCACHE":"/home/ldez/.cache/go-build", "GOROOT":"/home/ldez/.gvm/gos/go1.24.1"} 
INFO [lintersdb] Active 23 linters: [canonicalheader copyloopvar errcheck errname exptostd fatcontext gochecksumtype gofmt gofumpt gosimple iface inamedparam intrange misspell mnd nilnesserr perfsprint protogetter recvcheck sloglint spancheck testifylint usetesting] 
INFO [loader] Go packages loading at mode 8767 (exports_file|files|imports|types_sizes|compiled_files|deps|name) took 268.829843ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 6.312471ms 
WARN [linters_context] copyloopvar: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [linters_context/goanalysis] analyzers took 1.770311041s with top 10 stages: buildir: 461.235301ms, gofumpt: 185.804066ms, buildssa: 138.29144ms, gofmt: 108.798606ms, protogetter: 100.741209ms, misspell: 97.013646ms, testifylint: 64.117872ms, inspect: 62.568764ms, fact_purity: 49.355349ms, S1038: 42.875997ms 
WARN [linters_context] intrange: this linter is disabled because the Go version (1.21) of your project is lower than Go 1.22 
INFO [runner] Issues before processing: 444, after processing: 4 
INFO [runner] Processors filtering stat (in/out): severity-rules: 4/4, path_prettifier: 4/4, filename_unadjuster: 444/444, skip_files: 252/252, diff: 252/252, fixer: 252/252, max_per_file_from_linter: 4/4, source_code: 4/4, sort_results: 4/4, path_relativity: 252/252, exclusion_paths: 252/252, generated_file_filter: 252/252, identifier_marker: 252/252, exclusion_rules: 252/252, uniq_by_line: 252/4, max_same_issues: 4/4, path_shortener: 4/4, path_absoluter: 444/444, cgo: 444/444, skip_dirs: 252/252, max_from_linter: 4/4, invalid_issue: 444/252, nolint_filter: 252/252 
INFO [runner] processing took 294.66µs with stages: path_relativity: 146.771µs, source_code: 52.556µs, invalid_issue: 13.482µs, cgo: 12.403µs, uniq_by_line: 10.637µs, path_absoluter: 10.442µs, filename_unadjuster: 9.177µs, nolint_filter: 7.246µs, identifier_marker: 6.841µs, skip_dirs: 5.283µs, exclusion_rules: 5.153µs, generated_file_filter: 5.12µs, max_same_issues: 3.314µs, sort_results: 1.911µs, path_shortener: 1.854µs, max_from_linter: 578ns, exclusion_paths: 348ns, max_per_file_from_linter: 346ns, fixer: 335ns, diff: 263ns, skip_files: 244ns, path_prettifier: 192ns, severity-rules: 164ns 
INFO [runner] linters took 403.596191ms with stages: goanalysis_metalinter: 403.237097ms, copyloopvar: 5.709µs, intrange: 5.46µs 
internal/frontend/desktop/linux/calloc.go:9:8     typecheck  could not import C (cgo preprocessing failed)
internal/frontend/desktop/linux/frontend.go:94:2  typecheck  could not import github.com/wailsapp/wails/v2/pkg/assetserver/webview (-: # github.com/wailsapp/wails/v2/pkg/assetserver/webview
# [pkg-config --cflags  -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 webkit2gtk-4.0]
Package webkit2gtk-4.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `webkit2gtk-4.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found)
pkg/assetserver/assetserver_webview.go:11:2  typecheck  could not import github.com/wailsapp/wails/v2/pkg/assetserver/webview (-: # github.com/wailsapp/wails/v2/pkg/assetserver/webview
# [pkg-config --cflags  -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 webkit2gtk-4.0]
Package webkit2gtk-4.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `webkit2gtk-4.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found)
pkg/assetserver/webview/request.go:1  typecheck  : # github.com/wailsapp/wails/v2/pkg/assetserver/webview
# [pkg-config --cflags  -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 gtk+-3.0 webkit2gtk-4.0]
Package webkit2gtk-4.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `webkit2gtk-4.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found
Package 'webkit2gtk-4.0' not found
INFO File cache stats: 4 entries of total size 17.3KiB 
INFO Memory: 8 samples, avg is 113.7MB, max is 229.0MB 

@ldez
Copy link
Member

ldez commented Mar 17, 2025

So, my conclusions are unchanged #5546 (comment)

@ldez ldez changed the title Significant performance regression since 1.61 Significant performance regression since 1.62 Mar 17, 2025
@pfouilloux
Copy link
Author

pfouilloux commented Mar 17, 2025

Fair 🙂 Thanks for looking into it some more.

I'll have a go at running the linter against our repo in a linux container tomorrow morning to rule out the repo being the issue.

But, if we go with the assumption that it's something about the darwin platform and/or apple silicon hardware causing the difference - not unreasonable given these results. I did notice something interesting playing with the concurrency settings: I get a 1.5x speed boost when I align the max-concurrency setting with the number of performance cores on the mac... I suspect the p-cores get throttled down to e-core performance when work is shared between the two kinds of core.

I'll have a test tomorrow to see if that can bring the results in line with what we're seeing on linux 🙂

If it does improve performance up would you be open to a PR to try to autodetect the number of p-cores by default instead of defaulting to the number of availiable cores when we detect the program is running on darwin/arm64 arch?

It does look like it'd need to call out to sysctl as an external process though because the golang.org/x/sys/cpu package doesn't distinguish between core types on apple silicon 🙁 Something like this:

package main

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
)

func getCPUCoreCount(key string) int {
	cmd := exec.Command("sysctl", "-n", key)
	output, err := cmd.Output()
	if err != nil {
		fmt.Println("Error:", err)
		return -1
	}

	count, err := strconv.Atoi(strings.TrimSpace(string(output)))
	if err != nil {
		fmt.Println("Error converting to integer:", err)
		return -1
	}
	return count
}

func main() {
	pCores := getCPUCoreCount("hw.perflevel0.physicalcpu")
	eCores := getCPUCoreCount("hw.perflevel1.physicalcpu")
	totalCores := getCPUCoreCount("hw.ncpu")

	fmt.Println("Total Cores:", totalCores)
	fmt.Println("Performance Cores (P-Cores):", pCores)
	fmt.Println("Efficiency Cores (E-Cores):", eCores)
}

It may be better as a documentation piece though, given the reliance on the external process... Like saying: "If you're on an apple silicon mac and having perf issues try running with golangci-lint run -j $(sysctl -n hw.perflevel0.physicalcpu)"
source

What do you think?

In any case, I'll report if that makes a difference on my work laptop tomorrow 🙂

@pfouilloux
Copy link
Author

Hi 👋 I've run some benchmarks with our repo in a container and the timing is pretty consistent between versions, which supports the MacOS tooling/Apple silicon theory 🤔

To minimise the number of variables, I've added mise.jdx.dev to the alpine golang image and used it to swap between versions 1.61 and 1.62 of golangci-lint.

Note that I found it best to reproduce this by running the image in interactive mode as the first run took 2 minutes extra I suspect because of the initial go module download (though I suppose you could mount your GOMODCACHE)

INFO [loader] Go packages loading at mode 8767 (files|imports|name|compiled_files|deps|exports_file|types_sizes) took 2m5.74922911s

Docker VM resources: 4 vCPU, 16 GB RAM and 100 GB disk space. Using colima on darwin/arm64

FROM golang:1.23.6-alpine

RUN apk add mise bash

ENTRYPOINT ["/bin/bash"]
docker build -t lint:latest -f Dockerfile.lint .
docker run -v$(pwd):/opt/platform --workdir /opt/platform -it lint:latest
v1.61.3 - 1.40s
c8499a6d4dc9:/opt/platform# mise use [email protected] --pin -e local
mise [email protected] ✓ installed                                                                                                                                                                                                                                                                                           mise /opt/platform/mise.local.toml tools: [email protected]
c8499a6d4dc9:/opt/platform# golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v
golangci-lint has version 1.60.3 built with go1.23.0 from c2e095c0 on 2024-08-22T21:51:56Z
INFO golangci-lint has version 1.60.3 built with go1.23.0 from c2e095c0 on 2024-08-22T21:51:56Z 
INFO [config_reader] Config search paths: [./ /opt/platform /opt / /root] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (exports_file|files|imports|name|compiled_files|deps|types_sizes) took 10.658751586s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 764.694967ms 
INFO [linters_context/goanalysis] analyzers took 8m27.251651135s with top 10 stages: buildir: 1m43.931062911s, goimports: 1m8.59754532s, the_only_name: 1m4.351700256s, unconvert: 40.858679703s, gci: 25.951072644s, gofmt: 21.887892582s, buildssa: 15.025756725s, isgenerated: 12.979609916s, gocritic: 10.087582779s, S1038: 6.786682232s 
INFO [runner] Issues before processing: 12834, after processing: 0 
INFO [runner] Processors filtering stat (in/out): exclude-rules: 12834/32, cgo: 12834/12834, invalid_issue: 12834/12834, skip_dirs: 12834/12834, autogenerated_exclude: 12834/12834, path_prettifier: 12834/12834, identifier_marker: 12834/12834, nolint: 32/0, filename_unadjuster: 12834/12834, skip_files: 12834/12834, exclude: 12834/12834 
INFO [runner] processing took 2.172647905s with stages: autogenerated_exclude: 1.250429691s, path_prettifier: 615.528647ms, exclude-rules: 189.289557ms, identifier_marker: 95.304821ms, nolint: 14.222475ms, skip_dirs: 6.458048ms, cgo: 657.084µs, invalid_issue: 498.375µs, filename_unadjuster: 255.043µs, sort_results: 1.75µs, fixer: 542ns, uniq_by_line: 416ns, max_same_issues: 374ns, skip_files: 250ns, exclude: 208ns, diff: 207ns, max_per_file_from_linter: 124ns, source_code: 84ns, path_shortener: 84ns, severity-rules: 83ns, max_from_linter: 42ns, path_prefixer: 0s 
INFO [runner] linters took 1m29.043795123s with stages: goanalysis_metalinter: 1m26.871061757s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 948 samples, avg is 2508.8MB, max is 4396.3MB 
INFO Execution took 1m40.474908936s                
v1.61.3 - 1.41s
c8499a6d4dc9:/opt/platform# mise use [email protected] --pin -e local
mise /opt/platform/mise.local.toml tools: [email protected]
c8499a6d4dc9:/opt/platform# golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /opt/platform /opt / /root] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (types_sizes|compiled_files|deps|exports_file|files|imports|name) took 10.631702015s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 781.98425ms 
INFO [linters_context/goanalysis] analyzers took 8m43.277888102s with top 10 stages: goimports: 1m57.999601258s, buildir: 1m45.992456076s, the_only_name: 1m4.422165989s, unconvert: 42.460564876s, gci: 25.901922232s, gofmt: 19.828980168s, isgenerated: 9.629888206s, gocritic: 9.172382685s, S1038: 8.547340407s, buildssa: 6.52387462s 
INFO [runner] Issues before processing: 12832, after processing: 0 
INFO [runner] Processors filtering stat (in/out): filename_unadjuster: 12832/12832, skip_dirs: 12832/12832, autogenerated_exclude: 12832/12832, cgo: 12832/12832, identifier_marker: 12832/12832, nolint: 32/0, path_prettifier: 12832/12832, exclude-rules: 12832/32, invalid_issue: 12832/12832, skip_files: 12832/12832, exclude: 12832/12832 
INFO [runner] processing took 2.18639568s with stages: autogenerated_exclude: 1.264809457s, path_prettifier: 620.025674ms, exclude-rules: 183.500544ms, identifier_marker: 95.751486ms, nolint: 14.070849ms, skip_dirs: 6.575341ms, cgo: 835.543µs, invalid_issue: 519.543µs, filename_unadjuster: 302.917µs, max_same_issues: 1.167µs, sort_results: 708ns, uniq_by_line: 416ns, fixer: 374ns, exclude: 333ns, skip_files: 208ns, max_from_linter: 208ns, diff: 207ns, source_code: 207ns, severity-rules: 166ns, path_prefixer: 125ns, path_shortener: 124ns, max_per_file_from_linter: 83ns 
INFO [runner] linters took 1m30.297768131s with stages: goanalysis_metalinter: 1m28.111158112s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 936 samples, avg is 2574.1MB, max is 4708.5MB 
INFO Execution took 1m41.718912863s               

real	1m41.907s
user	2m45.259s
sys	0m16.448s

I'm testing a golangci-lint run -j $(sysctl -n hw.perflevel0.physicalcpu) like command now and will report back how that goes soon.

@pfouilloux
Copy link
Author

pfouilloux commented Mar 18, 2025

There's a measurable improvement when limiting concurrency to the number of p-cores, but there's still an almost 2x difference between the versions...

It definitely seems like it's prioritising using the p-cores though 🙂

Image

So there's something else at play that only seems to appear on the MacOS systems... Honestly if the docker version ran in ~40-50s I'd be tempted to just use that and call it a win but it's slower than v1.62.2 running directly on the OS so I'll keep digging 😅

go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v
v1.61.0 - 3.29s
go version go1.23.6 darwin/arm64
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (name|types_sizes|compiled_files|deps|exports_file|files|imports) took 10.58917875s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 123.912959ms 
INFO [linters_context/goanalysis] analyzers took 17m23.505375496s with top 10 stages: buildir: 2m25.309826148s, the_only_name: 1m18.691276598s, unconvert: 45.44887705s, gci: 30.626532746s, goimports: 24.421348332s, buildssa: 23.993643597s, gocritic: 16.610055968s, gofmt: 16.410399718s, S1038: 15.362389755s, printf: 10.75775629s 
INFO [runner] Issues before processing: 12834, after processing: 0 
INFO [runner] Processors filtering stat (in/out): skip_files: 12834/12834, nolint: 32/0, cgo: 12834/12834, exclude: 12834/12834, autogenerated_exclude: 12834/12834, path_prettifier: 12834/12834, skip_dirs: 12834/12834, identifier_marker: 12834/12834, exclude-rules: 12834/32, filename_unadjuster: 12834/12834, invalid_issue: 12834/12834 
INFO [runner] processing took 569.870043ms with stages: autogenerated_exclude: 237.738125ms, exclude-rules: 181.464084ms, identifier_marker: 112.437791ms, path_prettifier: 26.485334ms, skip_dirs: 5.534375ms, nolint: 4.609792ms, cgo: 654.583µs, invalid_issue: 626.709µs, filename_unadjuster: 314.292µs, sort_results: 3.125µs, max_same_issues: 375ns, skip_files: 291ns, fixer: 250ns, uniq_by_line: 208ns, source_code: 166ns, diff: 166ns, max_from_linter: 126ns, exclude: 83ns, max_per_file_from_linter: 42ns, severity-rules: 42ns, path_shortener: 42ns, path_prefixer: 42ns 
INFO [runner] linters took 28.458246625s with stages: goanalysis_metalinter: 27.888318833s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 355 samples, avg is 2289.5MB, max is 5101.2MB 
INFO Execution took 39.180799916s                 

________________________________________________________
Executed in   39.29 secs    fish           external
   usr time  272.40 secs   39.00 micros  272.40 secs
   sys time   38.08 secs  378.00 micros   38.08 secs
v1.62.2 - 100.09s
go version go1.23.6 darwin/arm64
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (compiled_files|files|types_sizes|deps|exports_file|imports|name) took 1.384177625s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 127.853875ms 
INFO [linters_context/goanalysis] analyzers took 1h5m16.621752704s with top 10 stages: buildir: 9m37.105639084s, goimports: 5m55.061141582s, the_only_name: 4m21.30165873s, unconvert: 2m50.109331617s, gci: 1m43.771902914s, gocritic: 1m11.670641958s, S1038: 59.874731262s, buildssa: 53.112994581s, gofmt: 52.089177502s, SA4030: 36.401640993s 
INFO [runner] Issues before processing: 12832, after processing: 0 
INFO [runner] Processors filtering stat (in/out): path_prettifier: 12832/12832, skip_dirs: 12832/12832, identifier_marker: 12832/12832, exclude-rules: 12832/32, cgo: 12832/12832, invalid_issue: 12832/12832, skip_files: 12832/12832, autogenerated_exclude: 12832/12832, filename_unadjuster: 12832/12832, exclude: 12832/12832, nolint: 32/0 
INFO [runner] processing took 565.819664ms with stages: autogenerated_exclude: 246.495125ms, exclude-rules: 177.980583ms, identifier_marker: 101.123167ms, path_prettifier: 27.839042ms, skip_dirs: 5.664625ms, nolint: 4.603708ms, invalid_issue: 917.083µs, cgo: 777.417µs, filename_unadjuster: 415µs, sort_results: 1.625µs, max_same_issues: 833ns, fixer: 250ns, exclude: 250ns, uniq_by_line: 208ns, skip_files: 207ns, source_code: 125ns, diff: 125ns, max_from_linter: 83ns, max_per_file_from_linter: 83ns, path_shortener: 42ns, path_prefixer: 42ns, severity-rules: 41ns 
INFO [runner] linters took 1m38.440556958s with stages: goanalysis_metalinter: 1m37.872460833s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 835 samples, avg is 3515.5MB, max is 5585.4MB 
INFO Execution took 1m39.962150083s               

________________________________________________________
Executed in  100.09 secs    fish           external
   usr time  230.22 secs   29.00 micros  230.22 secs
   sys time  216.23 secs  374.00 micros  216.23 secs
go version && golangci-lint --version && golangci-lint cache clean && time golangci-lint run -v -j $(sysctl -n hw.perflevel0.physicalcpu)
v1.61.0 - 39.12s
go version go1.23.6 darwin/arm64
golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z
INFO golangci-lint has version 1.61.0 built with go1.23.1 from a1d6c560 on 2024-09-09T17:44:42Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 575 (name|types_sizes|deps|exports_file|imports|compiled_files|files) took 1.3823175s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 152.462083ms 
INFO [linters_context/goanalysis] analyzers took 6m29.269952597s with top 10 stages: buildir: 1m18.666909522s, the_only_name: 54.714255021s, unconvert: 37.837630452s, gci: 19.916635122s, goimports: 16.77447141s, buildssa: 12.500773724s, gofmt: 8.818017148s, gocritic: 8.672861162s, S1038: 7.703543147s, fact_deprecated: 3.939625445s 
INFO [runner] Issues before processing: 12834, after processing: 0 
INFO [runner] Processors filtering stat (in/out): filename_unadjuster: 12834/12834, autogenerated_exclude: 12834/12834, exclude-rules: 12834/32, nolint: 32/0, cgo: 12834/12834, path_prettifier: 12834/12834, skip_files: 12834/12834, identifier_marker: 12834/12834, exclude: 12834/12834, invalid_issue: 12834/12834, skip_dirs: 12834/12834 
INFO [runner] processing took 535.076376ms with stages: autogenerated_exclude: 225.438208ms, exclude-rules: 181.483333ms, identifier_marker: 91.977459ms, path_prettifier: 25.170917ms, skip_dirs: 5.525875ms, nolint: 4.344459ms, cgo: 500.042µs, invalid_issue: 409.333µs, filename_unadjuster: 219.709µs, sort_results: 4.458µs, max_same_issues: 541ns, fixer: 334ns, skip_files: 292ns, uniq_by_line: 291ns, diff: 291ns, max_from_linter: 209ns, max_per_file_from_linter: 167ns, exclude: 167ns, path_prefixer: 125ns, path_shortener: 83ns, source_code: 42ns, severity-rules: 41ns 
INFO [runner] linters took 37.470220458s with stages: goanalysis_metalinter: 36.935084834s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 358 samples, avg is 2715.3MB, max is 4420.0MB 
INFO Execution took 39.014299292s                 

________________________________________________________
Executed in   39.12 secs    fish           external
   usr time  136.83 secs   32.00 micros  136.83 secs
   sys time   17.93 secs  349.00 micros   17.93 secs
v1.62.2 - 85.61
go version go1.23.6 darwin/arm64
golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z
INFO golangci-lint has version 1.62.2 built with go1.23.3 from 89476e7a on 2024-11-25T14:16:01Z 
INFO [config_reader] Config search paths: [./ /Users/pfx/code/2-areas/platform /Users/pfx/code/2-areas /Users/pfx/code /Users/pfx /Users /] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 20 linters: [depguard dogsled errcheck exhaustive gci gocritic gofmt goimports goprintffuncname gosimple govet makezero predeclared revive rowserrcheck staticcheck testpackage tparallel unconvert unused] 
INFO [loader] Using build tags: [integration]     
INFO [loader] Go packages loading at mode 8767 (name|imports|types_sizes|compiled_files|deps|exports_file|files) took 1.395076917s 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 162.230167ms 
INFO [linters_context/goanalysis] analyzers took 16m24.430219473s with top 10 stages: buildir: 2m52.640745354s, goimports: 2m39.97782849s, the_only_name: 1m57.396418742s, unconvert: 1m24.730112573s, gci: 42.287203252s, gocritic: 17.996702209s, S1038: 15.009453953s, gofmt: 13.534480101s, buildssa: 13.387924344s, fact_deprecated: 7.046468587s 
INFO [runner] Issues before processing: 12832, after processing: 0 
INFO [runner] Processors filtering stat (in/out): invalid_issue: 12832/12832, path_prettifier: 12832/12832, autogenerated_exclude: 12832/12832, exclude-rules: 12832/32, cgo: 12832/12832, identifier_marker: 12832/12832, skip_files: 12832/12832, nolint: 32/0, exclude: 12832/12832, skip_dirs: 12832/12832, filename_unadjuster: 12832/12832 
INFO [runner] processing took 601.68854ms with stages: autogenerated_exclude: 273.273459ms, exclude-rules: 184.89975ms, identifier_marker: 102.406584ms, path_prettifier: 28.898083ms, skip_dirs: 5.650834ms, nolint: 4.913667ms, invalid_issue: 684.166µs, cgo: 580.374µs, filename_unadjuster: 377µs, sort_results: 2.125µs, max_same_issues: 791ns, skip_files: 292ns, exclude: 291ns, fixer: 291ns, uniq_by_line: 250ns, max_from_linter: 167ns, source_code: 125ns, diff: 125ns, severity-rules: 84ns, path_shortener: 41ns, max_per_file_from_linter: 41ns, path_prefixer: 0s 
INFO [runner] linters took 1m23.924599792s with stages: goanalysis_metalinter: 1m23.322661375s 
INFO File cache stats: 8 entries of total size 132.3KiB 
INFO Memory: 719 samples, avg is 3056.5MB, max is 5089.0MB 
INFO Execution took 1m25.4913845s                 

________________________________________________________
Executed in   85.61 secs    fish           external
   usr time  153.88 secs   29.00 micros  153.88 secs
   sys time  107.58 secs  316.00 micros  107.58 secs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feedback required Requires additional feedback platform: macos Issue that is related to MacOS question Further information is requested topic: speed
Projects
None yet
Development

No branches or pull requests

2 participants