-
Notifications
You must be signed in to change notification settings - Fork 1
version 1.2.4 #12
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
Merged
Merged
version 1.2.4 #12
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module SmarterJSON | ||
| # Pure (mkmf-free) selection of CPU-optimization flags from the | ||
| # SMARTER_JSON_PERFORMANCE environment variable. Kept separate from extconf.rb | ||
| # so the logic can be unit-tested without invoking a compiler. | ||
| # | ||
| # Levels: | ||
| # portable - no host-specific flags. The binary runs on any CPU of the same | ||
| # architecture. The safe default: a binary built here will not | ||
| # crash with "Illegal instruction" on an older/different CPU. | ||
| # tuned - -mtune=native: tunes instruction scheduling for the build host's | ||
| # microarchitecture WITHOUT changing the instruction set, so the | ||
| # binary stays portable. A real win when build and run hosts share | ||
| # a microarchitecture (same chip or a homogeneous fleet). | ||
| # max - host-specific instructions: -march=native, or -mcpu=native on | ||
| # ARM/Clang where -march=native is rejected. Fastest, but NOT | ||
| # portable -- may crash on a CPU lacking the build host's | ||
| # instructions. Use only when build host and run host match. | ||
| # | ||
| # `accepts` is a predicate (in the real build, a wrapper over mkmf's | ||
| # try_compile) returning true when the compiler accepts a given flag; each | ||
| # candidate is probed so an unsupported flag is skipped rather than breaking | ||
| # the build. | ||
| module CpuFlags | ||
| LEVELS = %w[portable tuned max].freeze | ||
|
|
||
| # Candidate flags per level, in preference order. The first one the compiler | ||
| # accepts wins. `max` degrades march -> mcpu -> mtune; tuned only ever | ||
| # considers -mtune=native (never an instruction-set flag). | ||
| CANDIDATES = { | ||
| 'portable' => [].freeze, | ||
| 'tuned' => ['-mtune=native'].freeze, | ||
| 'max' => ['-march=native', '-mcpu=native', '-mtune=native'].freeze, | ||
| }.freeze | ||
|
|
||
| # Returns a Hash: { level: String, flags: Array<String>, warning: String|nil }. | ||
| def self.select(raw_level, accepts:) | ||
| level, warning = normalize(raw_level) | ||
| chosen = CANDIDATES[level].find { |flag| accepts.call(flag) } | ||
| { level: level, flags: chosen ? [chosen] : [], warning: warning } | ||
| end | ||
|
|
||
| # Normalizes the env value to a known level. Unknown values fall back to | ||
| # 'portable' (a typo can then only ever be slower, never non-portable) and | ||
| # return a warning naming the bad value and the fallback. | ||
| def self.normalize(raw_level) | ||
| value = raw_level.to_s.strip.downcase | ||
| return ['portable', nil] if value.empty? | ||
| return [value, nil] if LEVELS.include?(value) | ||
|
|
||
| ['portable', "SMARTER_JSON_PERFORMANCE=#{raw_level.inspect} is not one of #{LEVELS.join('|')}; using 'portable'."] | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module SmarterJSON | ||
| VERSION = "1.2.3" | ||
| VERSION = "1.2.4" | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require_relative "../ext/smarter_json/cpu_flags" | ||
|
|
||
| # Contract for the pure (mkmf-free) CPU-optimization flag selector used by | ||
| # ext/smarter_json/extconf.rb. It maps SMARTER_JSON_PERFORMANCE to the list of | ||
| # host flags to append, asking the supplied `accepts` predicate (which wraps the | ||
| # compiler probe in the real build) whether each candidate flag compiles. | ||
| # | ||
| # Safety contract: the default (and any unknown value) must NEVER add a | ||
| # host-specific instruction-set flag (-march/-mcpu native), because that is what | ||
| # makes a binary crash with "Illegal instruction" on a CPU that lacks the build | ||
| # host's instructions. | ||
| RSpec.describe SmarterJSON::CpuFlags do | ||
| let(:accepts_all) { ->(_flag) { true } } | ||
| let(:accepts_none) { ->(_flag) { false } } | ||
|
|
||
| def select(level, accepts: accepts_all) | ||
| described_class.select(level, accepts: accepts) | ||
| end | ||
|
|
||
| describe "portable (the default)" do | ||
| it "defaults to portable when the value is nil" do | ||
| result = select(nil) | ||
| expect(result[:level]).to eq "portable" | ||
| expect(result[:flags]).to eq [] | ||
| expect(result[:warning]).to be_nil | ||
| end | ||
|
|
||
| it "defaults to portable when the value is empty" do | ||
| expect(select("")[:level]).to eq "portable" | ||
| end | ||
|
|
||
| it "adds no host flags even when the compiler would accept every flag" do | ||
| expect(select("portable", accepts: accepts_all)[:flags]).to eq [] | ||
| end | ||
|
|
||
| it "is case-insensitive" do | ||
| expect(select("PORTABLE")[:level]).to eq "portable" | ||
| end | ||
|
|
||
| it "ignores surrounding whitespace" do | ||
| expect(select(" portable ")[:level]).to eq "portable" | ||
| end | ||
| end | ||
|
|
||
| describe "tuned" do | ||
| it "adds -mtune=native when the compiler accepts it" do | ||
| expect(select("tuned", accepts: accepts_all)[:flags]).to eq ["-mtune=native"] | ||
| end | ||
|
|
||
| it "adds nothing when the compiler rejects -mtune=native (e.g. MSVC)" do | ||
| expect(select("tuned", accepts: accepts_none)[:flags]).to eq [] | ||
| end | ||
|
|
||
| it "never adds an instruction-set flag (-march/-mcpu)" do | ||
| flags = select("tuned", accepts: accepts_all)[:flags] | ||
| expect(flags).not_to include("-march=native") | ||
| expect(flags).not_to include("-mcpu=native") | ||
| end | ||
| end | ||
|
|
||
| describe "max" do | ||
| it "prefers -march=native when the compiler accepts it" do | ||
| expect(select("max", accepts: accepts_all)[:flags]).to eq ["-march=native"] | ||
| end | ||
|
|
||
| it "falls back to -mcpu=native when -march=native is rejected (e.g. Clang on ARM)" do | ||
| accepts = ->(flag) { flag != "-march=native" } | ||
| expect(select("max", accepts: accepts)[:flags]).to eq ["-mcpu=native"] | ||
| end | ||
|
|
||
| it "falls back to -mtune=native when both -march and -mcpu are rejected" do | ||
| accepts = ->(flag) { flag == "-mtune=native" } | ||
| expect(select("max", accepts: accepts)[:flags]).to eq ["-mtune=native"] | ||
| end | ||
|
|
||
| it "adds nothing when the compiler rejects every candidate (e.g. MSVC)" do | ||
| expect(select("max", accepts: accepts_none)[:flags]).to eq [] | ||
| end | ||
| end | ||
|
|
||
| describe "unknown / typo values" do | ||
| it "falls back to portable so a typo can only ever be slower, never non-portable" do | ||
| result = select("fast") | ||
| expect(result[:level]).to eq "portable" | ||
| expect(result[:flags]).to eq [] | ||
| end | ||
|
|
||
| it "warns, naming the bad value and the level it fell back to" do | ||
| warning = select("fast")[:warning] | ||
| expect(warning).to include("fast") | ||
| expect(warning).to include("portable") | ||
| end | ||
| end | ||
| end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.