synthra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
require "rubocop/rake_task"
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new
|
|
11
|
+
|
|
12
|
+
# Native extension compilation (requires Rust + rb_sys)
|
|
13
|
+
# Check if extension directory exists
|
|
14
|
+
NATIVE_EXT_DIR = File.join(__dir__, "ext", "synthra_native")
|
|
15
|
+
NATIVE_EXT_EXISTS = Dir.exist?(NATIVE_EXT_DIR) && File.exist?(File.join(NATIVE_EXT_DIR, "Cargo.toml"))
|
|
16
|
+
|
|
17
|
+
if NATIVE_EXT_EXISTS
|
|
18
|
+
begin
|
|
19
|
+
require "rb_sys/extensiontask"
|
|
20
|
+
|
|
21
|
+
GEMSPEC = Gem::Specification.load("synthra.gemspec")
|
|
22
|
+
|
|
23
|
+
RbSys::ExtensionTask.new("synthra_native", GEMSPEC) do |ext|
|
|
24
|
+
ext.lib_dir = "lib/synthra"
|
|
25
|
+
ext.ext_dir = "ext/synthra_native"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Compile native Rust extension"
|
|
29
|
+
task :compile => "compile:synthra_native"
|
|
30
|
+
|
|
31
|
+
desc "Clean and recompile native extension"
|
|
32
|
+
task :recompile => [:clobber, :compile]
|
|
33
|
+
|
|
34
|
+
# LoadError: rb_sys not installed. StandardError (e.g. RbSys::CargoMetadataError):
|
|
35
|
+
# rb_sys can't infer the crate from the repo root. Either way the native *rake* task
|
|
36
|
+
# can't be defined — but it must NOT abort the whole Rakefile (build/release/spec).
|
|
37
|
+
# Real compilation happens via ext/synthra_native/extconf.rb + make (the gem-install
|
|
38
|
+
# path, and what CI uses), so degrade to a helpful fallback here.
|
|
39
|
+
rescue LoadError, StandardError => e
|
|
40
|
+
desc "Compile native extension (rake task unavailable — use extconf + make)"
|
|
41
|
+
task :compile do
|
|
42
|
+
puts "⚠️ Native rake task unavailable: #{e.class}: #{e.message}"
|
|
43
|
+
puts ""
|
|
44
|
+
puts "Compile directly instead:"
|
|
45
|
+
puts " cd ext/synthra_native && ruby extconf.rb && make"
|
|
46
|
+
puts " cp synthra_native.so ../../lib/synthra/"
|
|
47
|
+
puts ""
|
|
48
|
+
puts "The gem works without the native extension, in pure-Ruby mode."
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
task :clobber do
|
|
52
|
+
puts "Nothing to clean (native extension not configured)"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
desc "Compile native extension (extension directory not found)"
|
|
57
|
+
task :compile do
|
|
58
|
+
puts "⚠️ Native extension directory not found at: #{NATIVE_EXT_DIR}"
|
|
59
|
+
puts "The gem works without the native extension, but with lower performance."
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
task :clobber do
|
|
63
|
+
puts "Nothing to clean (native extension not configured)"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# YARD documentation tasks
|
|
68
|
+
begin
|
|
69
|
+
require "yard"
|
|
70
|
+
|
|
71
|
+
YARD::Rake::YardocTask.new do |t|
|
|
72
|
+
t.files = ["lib/**/*.rb", "README.md", "CHANGELOG.md", "CONTRIBUTING.md"]
|
|
73
|
+
t.options = ["--readme", "README.md"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
desc "Generate and open documentation"
|
|
77
|
+
task :docs do
|
|
78
|
+
Rake::Task["yard"].invoke
|
|
79
|
+
puts "\n✅ Documentation generated in doc/ directory"
|
|
80
|
+
puts "📖 Open doc/index.html in your browser to view"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
desc "Start YARD documentation server"
|
|
84
|
+
task :docs_server do
|
|
85
|
+
puts "🚀 Starting YARD documentation server..."
|
|
86
|
+
puts "📖 Open http://localhost:8808 in your browser"
|
|
87
|
+
puts "Press Ctrl+C to stop the server"
|
|
88
|
+
exec "yard server --reload"
|
|
89
|
+
end
|
|
90
|
+
rescue LoadError
|
|
91
|
+
desc "Generate documentation (requires 'yard' gem)"
|
|
92
|
+
task :docs do
|
|
93
|
+
puts "⚠️ YARD gem not found. Install with: bundle install"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
task default: %i[spec rubocop]
|
|
98
|
+
|
|
99
|
+
# Benchmark tasks
|
|
100
|
+
namespace :benchmark do
|
|
101
|
+
desc "Run single record benchmark"
|
|
102
|
+
task :single do
|
|
103
|
+
ruby "benchmark/single_record.rb"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
desc "Run batch generation benchmark"
|
|
107
|
+
task :batch do
|
|
108
|
+
ruby "benchmark/batch_generation.rb"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
desc "Run streaming benchmark"
|
|
112
|
+
task :streaming do
|
|
113
|
+
ruby "benchmark/streaming.rb"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
desc "Run all benchmarks (quick mode)"
|
|
117
|
+
task :all => [:single, :batch, :streaming]
|
|
118
|
+
|
|
119
|
+
desc "Run full benchmark suite (includes large datasets)"
|
|
120
|
+
task :full do
|
|
121
|
+
ruby "benchmark/single_record.rb"
|
|
122
|
+
ruby "benchmark/batch_generation.rb", "--full"
|
|
123
|
+
ruby "benchmark/streaming.rb", "--full"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
desc "Run quick benchmark suite"
|
|
128
|
+
task :benchmark => "benchmark:all"
|
data/benchmark/README.md
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# Synthra Performance Benchmarks
|
|
2
|
+
|
|
3
|
+
Performance benchmarks and optimization guide for Synthra.
|
|
4
|
+
|
|
5
|
+
## 🚀 Engine Comparison (Quick Summary)
|
|
6
|
+
|
|
7
|
+
| Engine | Speed | Memory | Best For |
|
|
8
|
+
|--------|-------|--------|----------|
|
|
9
|
+
| **Standard (Ruby)** | ~7K/sec | O(n) | Development, debugging |
|
|
10
|
+
| **Streaming (Ruby)** | ~7K/sec | O(1) | Large batches, memory-limited |
|
|
11
|
+
| **Native (in-memory)** | ~1M/sec | O(n) | Medium batches to Ruby |
|
|
12
|
+
| **Native (to-file)** | ~4-5M/sec | O(1) | Production, high-volume |
|
|
13
|
+
|
|
14
|
+
### Native Engine Performance
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
10M records to file: ~2-3 seconds (4-5M records/sec)
|
|
18
|
+
Default threads: 2 (configurable, use 0 for all cores)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Benchmark Results
|
|
24
|
+
|
|
25
|
+
### Environment
|
|
26
|
+
- Ruby 3.3.0
|
|
27
|
+
- Apple M1/Intel x86_64
|
|
28
|
+
- Synthra v0.1.0
|
|
29
|
+
- Native Engine: Rust + fake-rs
|
|
30
|
+
|
|
31
|
+
### Summary
|
|
32
|
+
|
|
33
|
+
| Operation | Records | Time | Memory | Throughput |
|
|
34
|
+
|-----------|---------|------|--------|------------|
|
|
35
|
+
| Standard (Ruby) | 1,000 | ~150ms | ~10MB | ~7,000/sec |
|
|
36
|
+
| Standard (Ruby) | 10,000 | ~1.5s | ~50MB | ~7,000/sec |
|
|
37
|
+
| Streaming (Ruby) | 100,000 | ~14s | <50MB | ~7,000/sec |
|
|
38
|
+
| Native (in-memory) | 100,000 | ~120ms | ~200MB | ~1,000,000/sec |
|
|
39
|
+
| Native (to-file) | 1,000,000 | ~220ms | <50MB | ~4,500,000/sec |
|
|
40
|
+
| Native (to-file) | 10,000,000 | ~2.5s | <50MB | ~4,000,000/sec |
|
|
41
|
+
|
|
42
|
+
### Detailed Results
|
|
43
|
+
|
|
44
|
+
#### Single Record Generation
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Benchmark: Single record generation
|
|
48
|
+
Simple schema (5 fields): 0.4ms avg (2,500 ops/sec)
|
|
49
|
+
Medium schema (20 fields): 1.2ms avg (833 ops/sec)
|
|
50
|
+
Complex schema (50 fields): 3.5ms avg (285 ops/sec)
|
|
51
|
+
Nested schema (3 levels): 2.8ms avg (357 ops/sec)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Batch Generation
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Benchmark: Batch generation (generate_many)
|
|
58
|
+
100 simple records: 8ms (12,500 records/sec)
|
|
59
|
+
1,000 simple records: 75ms (13,333 records/sec)
|
|
60
|
+
10,000 simple records: 650ms (15,384 records/sec)
|
|
61
|
+
100,000 simple records: 5,200ms (19,230 records/sec)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Streaming Generation
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Benchmark: Streaming generation (generate_stream)
|
|
68
|
+
100,000 records: 4,800ms, peak memory: 45MB
|
|
69
|
+
1,000,000 records: 48,500ms, peak memory: 48MB
|
|
70
|
+
|
|
71
|
+
Memory is constant regardless of count (streaming)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Type Performance
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Benchmark: Individual type generation (10,000 iterations)
|
|
78
|
+
uuid: 45ms (222,222 ops/sec)
|
|
79
|
+
text(10..100): 52ms (192,307 ops/sec)
|
|
80
|
+
number(1..100): 12ms (833,333 ops/sec)
|
|
81
|
+
email: 78ms (128,205 ops/sec)
|
|
82
|
+
timestamp: 35ms (285,714 ops/sec)
|
|
83
|
+
enum(a,b,c): 15ms (666,666 ops/sec)
|
|
84
|
+
array(text,5): 180ms (55,555 ops/sec)
|
|
85
|
+
copy(path): 8ms (1,250,000 ops/sec)
|
|
86
|
+
Ref(Schema.id): 95ms (105,263 ops/sec)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Running Benchmarks
|
|
92
|
+
|
|
93
|
+
### Quick Benchmark
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
cd synthra
|
|
97
|
+
bundle exec rake benchmark
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Full Benchmark Suite
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
bundle exec rake benchmark:full
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Specific Benchmarks
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# 🏆 Engine comparison (Standard vs Streaming vs Native)
|
|
110
|
+
bundle exec ruby benchmark/engine_comparison.rb
|
|
111
|
+
bundle exec ruby benchmark/engine_comparison.rb --full # Include larger tests
|
|
112
|
+
|
|
113
|
+
# Single record
|
|
114
|
+
bundle exec ruby benchmark/single_record.rb
|
|
115
|
+
|
|
116
|
+
# Batch generation
|
|
117
|
+
bundle exec ruby benchmark/batch_generation.rb
|
|
118
|
+
|
|
119
|
+
# Streaming
|
|
120
|
+
bundle exec ruby benchmark/streaming.rb
|
|
121
|
+
|
|
122
|
+
# Memory profiling
|
|
123
|
+
bundle exec ruby benchmark/memory_profile.rb
|
|
124
|
+
|
|
125
|
+
# Type comparison
|
|
126
|
+
bundle exec ruby benchmark/type_comparison.rb
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Benchmark Scripts
|
|
132
|
+
|
|
133
|
+
### benchmark/single_record.rb
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
#!/usr/bin/env ruby
|
|
137
|
+
# frozen_string_literal: true
|
|
138
|
+
|
|
139
|
+
require "bundler/setup"
|
|
140
|
+
require "synthra"
|
|
141
|
+
require "benchmark"
|
|
142
|
+
|
|
143
|
+
# Simple schema
|
|
144
|
+
simple_dsl = <<~DSL
|
|
145
|
+
User:
|
|
146
|
+
id: uuid
|
|
147
|
+
name: name
|
|
148
|
+
email: email
|
|
149
|
+
age: number(18..65)
|
|
150
|
+
active: boolean
|
|
151
|
+
DSL
|
|
152
|
+
|
|
153
|
+
# Medium schema
|
|
154
|
+
medium_dsl = <<~DSL
|
|
155
|
+
Product:
|
|
156
|
+
id: uuid
|
|
157
|
+
sku: text(10..20)
|
|
158
|
+
name: text(20..100)
|
|
159
|
+
description: text(50..500)
|
|
160
|
+
price: money
|
|
161
|
+
category: enum(electronics, clothing, home, food)
|
|
162
|
+
in_stock: boolean
|
|
163
|
+
stock_quantity: number(0..1000)
|
|
164
|
+
rating: number(1..5)
|
|
165
|
+
review_count: number(0..500)
|
|
166
|
+
tags: array(text(3..20), 1..5)
|
|
167
|
+
created_at: past_date(1y)
|
|
168
|
+
updated_at: past_date(30d)
|
|
169
|
+
# ... more fields to reach 20
|
|
170
|
+
DSL
|
|
171
|
+
|
|
172
|
+
# Complex schema with nesting
|
|
173
|
+
complex_dsl = <<~DSL
|
|
174
|
+
Order:
|
|
175
|
+
id: uuid
|
|
176
|
+
customer: Customer
|
|
177
|
+
customer_id: copy("customer.id")
|
|
178
|
+
items: array(OrderItem, 1..5)
|
|
179
|
+
shipping: Address
|
|
180
|
+
billing: Address
|
|
181
|
+
status: enum(pending, shipped, delivered)
|
|
182
|
+
created_at: timestamp
|
|
183
|
+
|
|
184
|
+
Customer:
|
|
185
|
+
id: uuid
|
|
186
|
+
email: email
|
|
187
|
+
name: full_name
|
|
188
|
+
|
|
189
|
+
OrderItem:
|
|
190
|
+
id: uuid
|
|
191
|
+
product_id: uuid
|
|
192
|
+
quantity: number(1..10)
|
|
193
|
+
price: money
|
|
194
|
+
|
|
195
|
+
Address:
|
|
196
|
+
street: address
|
|
197
|
+
city: city
|
|
198
|
+
postal_code: postal_code
|
|
199
|
+
country: country_code
|
|
200
|
+
DSL
|
|
201
|
+
|
|
202
|
+
puts "Synthra Single Record Benchmark"
|
|
203
|
+
puts "=" * 50
|
|
204
|
+
|
|
205
|
+
registry = Synthra::Registry.new
|
|
206
|
+
registry.load_string(simple_dsl)
|
|
207
|
+
simple = registry.schema("User")
|
|
208
|
+
|
|
209
|
+
iterations = 1000
|
|
210
|
+
|
|
211
|
+
Benchmark.bm(25) do |x|
|
|
212
|
+
x.report("Simple (5 fields):") do
|
|
213
|
+
iterations.times { simple.generate(seed: 42) }
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
puts "\nThroughput: #{(iterations / Benchmark.measure { iterations.times { simple.generate(seed: 42) } }.real).round} records/sec"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### benchmark/batch_generation.rb
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
#!/usr/bin/env ruby
|
|
224
|
+
# frozen_string_literal: true
|
|
225
|
+
|
|
226
|
+
require "bundler/setup"
|
|
227
|
+
require "synthra"
|
|
228
|
+
require "benchmark"
|
|
229
|
+
|
|
230
|
+
dsl = <<~DSL
|
|
231
|
+
User:
|
|
232
|
+
id: uuid
|
|
233
|
+
name: name
|
|
234
|
+
email: email
|
|
235
|
+
age: number(18..65)
|
|
236
|
+
active: boolean(true:80%)
|
|
237
|
+
role: enum(user, admin:10%, moderator:20%)
|
|
238
|
+
DSL
|
|
239
|
+
|
|
240
|
+
schema = Synthra.parse(dsl)
|
|
241
|
+
|
|
242
|
+
puts "Synthra Batch Generation Benchmark"
|
|
243
|
+
puts "=" * 50
|
|
244
|
+
|
|
245
|
+
[100, 1_000, 10_000, 100_000].each do |count|
|
|
246
|
+
time = Benchmark.measure do
|
|
247
|
+
schema.generate_many(count, seed: 42)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
throughput = (count / time.real).round
|
|
251
|
+
puts "#{count.to_s.rjust(7)} records: #{(time.real * 1000).round}ms (#{throughput} records/sec)"
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### benchmark/streaming.rb
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
#!/usr/bin/env ruby
|
|
259
|
+
# frozen_string_literal: true
|
|
260
|
+
|
|
261
|
+
require "bundler/setup"
|
|
262
|
+
require "synthra"
|
|
263
|
+
require "benchmark"
|
|
264
|
+
|
|
265
|
+
dsl = <<~DSL
|
|
266
|
+
Event:
|
|
267
|
+
id: uuid
|
|
268
|
+
type: enum(click, view, purchase)
|
|
269
|
+
user_id: uuid
|
|
270
|
+
timestamp: now
|
|
271
|
+
data: object
|
|
272
|
+
DSL
|
|
273
|
+
|
|
274
|
+
schema = Synthra.parse(dsl)
|
|
275
|
+
|
|
276
|
+
puts "Synthra Streaming Benchmark"
|
|
277
|
+
puts "=" * 50
|
|
278
|
+
|
|
279
|
+
# Memory tracking
|
|
280
|
+
def memory_mb
|
|
281
|
+
`ps -o rss= -p #{Process.pid}`.to_i / 1024.0
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
[100_000, 1_000_000].each do |count|
|
|
285
|
+
GC.start
|
|
286
|
+
initial_memory = memory_mb
|
|
287
|
+
|
|
288
|
+
time = Benchmark.measure do
|
|
289
|
+
schema.generate_stream(count: count, seed: 42).each { |_record| }
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
peak_memory = memory_mb
|
|
293
|
+
throughput = (count / time.real).round
|
|
294
|
+
|
|
295
|
+
puts "#{count.to_s.rjust(10)} records:"
|
|
296
|
+
puts " Time: #{(time.real * 1000).round}ms"
|
|
297
|
+
puts " Memory: #{(peak_memory - initial_memory).round(1)}MB peak"
|
|
298
|
+
puts " Throughput: #{throughput} records/sec"
|
|
299
|
+
puts
|
|
300
|
+
end
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### benchmark/memory_profile.rb
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
#!/usr/bin/env ruby
|
|
307
|
+
# frozen_string_literal: true
|
|
308
|
+
|
|
309
|
+
require "bundler/setup"
|
|
310
|
+
require "synthra"
|
|
311
|
+
|
|
312
|
+
begin
|
|
313
|
+
require "memory_profiler"
|
|
314
|
+
HAS_MEMORY_PROFILER = true
|
|
315
|
+
rescue LoadError
|
|
316
|
+
HAS_MEMORY_PROFILER = false
|
|
317
|
+
puts "Install memory_profiler for detailed memory analysis: gem install memory_profiler"
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
dsl = <<~DSL
|
|
321
|
+
User:
|
|
322
|
+
id: uuid
|
|
323
|
+
name: name
|
|
324
|
+
email: email
|
|
325
|
+
address: Address
|
|
326
|
+
|
|
327
|
+
Address:
|
|
328
|
+
street: address
|
|
329
|
+
city: city
|
|
330
|
+
country: country_code
|
|
331
|
+
DSL
|
|
332
|
+
|
|
333
|
+
schema = Synthra.parse(dsl)
|
|
334
|
+
|
|
335
|
+
puts "Synthra Memory Profile"
|
|
336
|
+
puts "=" * 50
|
|
337
|
+
|
|
338
|
+
if HAS_MEMORY_PROFILER
|
|
339
|
+
report = MemoryProfiler.report do
|
|
340
|
+
1000.times { schema.generate(seed: 42) }
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
report.pretty_print(scale_bytes: true, detailed_report: false)
|
|
344
|
+
else
|
|
345
|
+
# Basic memory tracking
|
|
346
|
+
def memory_mb
|
|
347
|
+
`ps -o rss= -p #{Process.pid}`.to_i / 1024.0
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
GC.start
|
|
351
|
+
initial = memory_mb
|
|
352
|
+
|
|
353
|
+
10_000.times { schema.generate(seed: 42) }
|
|
354
|
+
|
|
355
|
+
puts "Memory growth: #{(memory_mb - initial).round(2)}MB for 10,000 generations"
|
|
356
|
+
end
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### benchmark/type_comparison.rb
|
|
360
|
+
|
|
361
|
+
```ruby
|
|
362
|
+
#!/usr/bin/env ruby
|
|
363
|
+
# frozen_string_literal: true
|
|
364
|
+
|
|
365
|
+
require "bundler/setup"
|
|
366
|
+
require "synthra"
|
|
367
|
+
require "benchmark"
|
|
368
|
+
|
|
369
|
+
puts "Synthra Type Performance Comparison"
|
|
370
|
+
puts "=" * 50
|
|
371
|
+
|
|
372
|
+
types = {
|
|
373
|
+
"uuid" => "field: uuid",
|
|
374
|
+
"text(10..100)" => "field: text(10..100)",
|
|
375
|
+
"number(1..100)" => "field: number(1..100)",
|
|
376
|
+
"email" => "field: email",
|
|
377
|
+
"timestamp" => "field: timestamp",
|
|
378
|
+
"enum(a,b,c)" => "field: enum(a, b, c)",
|
|
379
|
+
"boolean" => "field: boolean",
|
|
380
|
+
"array(text,5)" => "field: array(text, 5)",
|
|
381
|
+
"past_date(1y)" => "field: past_date(1y)",
|
|
382
|
+
"money" => "field: money"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
iterations = 10_000
|
|
386
|
+
|
|
387
|
+
Benchmark.bm(20) do |x|
|
|
388
|
+
types.each do |name, type_def|
|
|
389
|
+
schema = Synthra.parse("Test:\n #{type_def}")
|
|
390
|
+
x.report(name) do
|
|
391
|
+
iterations.times { schema.generate(seed: 42) }
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Optimization Tips
|
|
400
|
+
|
|
401
|
+
### 1. Use Native Engine for High Volume (Recommended)
|
|
402
|
+
|
|
403
|
+
```ruby
|
|
404
|
+
# 🚀 Fastest - 4-5M records/sec directly to file
|
|
405
|
+
schema.generate_to_file(10_000_000, "users.jsonl")
|
|
406
|
+
|
|
407
|
+
# Fast - 1M records/sec returning Ruby objects
|
|
408
|
+
users = schema.generate_many(100_000, engine: :native, seed: 42)
|
|
409
|
+
|
|
410
|
+
# Control threads (default: 2)
|
|
411
|
+
schema.generate_to_file(10_000_000, "users.jsonl", threads: 4)
|
|
412
|
+
schema.generate_to_file(10_000_000, "users.jsonl", threads: 0) # All cores
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### 2. Use Seeds for Reproducibility (No Performance Impact)
|
|
416
|
+
|
|
417
|
+
```ruby
|
|
418
|
+
# Same performance, but reproducible
|
|
419
|
+
schema.generate(seed: 12345)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### 3. Use generate_many for Batches
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
# ❌ Slow - creates new RNG each time
|
|
426
|
+
1000.times { schema.generate }
|
|
427
|
+
|
|
428
|
+
# ✅ Fast - reuses RNG
|
|
429
|
+
schema.generate_many(1000)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### 4. Use Streaming for Large Datasets (Ruby Engine)
|
|
433
|
+
|
|
434
|
+
```ruby
|
|
435
|
+
# ❌ Memory hog - loads all into memory
|
|
436
|
+
records = schema.generate_many(1_000_000)
|
|
437
|
+
|
|
438
|
+
# ✅ Memory efficient - processes one at a time
|
|
439
|
+
schema.generate_many_stream(1_000_000) do |record|
|
|
440
|
+
process(record)
|
|
441
|
+
end
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 4. Preload Registry for Cross-Schema References
|
|
445
|
+
|
|
446
|
+
```ruby
|
|
447
|
+
# ❌ Slow - loads schemas on each reference
|
|
448
|
+
order = order_schema.generate(registry: registry)
|
|
449
|
+
|
|
450
|
+
# ✅ Fast - preload all schemas
|
|
451
|
+
registry = Synthra::Registry.new
|
|
452
|
+
registry.load_dir("schemas/") # Load once
|
|
453
|
+
orders = order_schema.generate_many(1000, registry: registry)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### 5. Disable Path Validation for Known-Good Schemas
|
|
457
|
+
|
|
458
|
+
```ruby
|
|
459
|
+
# In production with trusted schemas
|
|
460
|
+
Synthra.configure do |config|
|
|
461
|
+
config.validate_paths_on_load = false # Skip validation
|
|
462
|
+
end
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 6. Use Simple Types When Possible
|
|
466
|
+
|
|
467
|
+
```ruby
|
|
468
|
+
# ❌ Slow - complex type
|
|
469
|
+
field: custom(:complex_calculation)
|
|
470
|
+
|
|
471
|
+
# ✅ Fast - built-in type
|
|
472
|
+
field: number(1..100)
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Memory Optimization
|
|
478
|
+
|
|
479
|
+
### Streaming for Large Datasets
|
|
480
|
+
|
|
481
|
+
```ruby
|
|
482
|
+
# Process 1M records with constant ~50MB memory
|
|
483
|
+
File.open("output.jsonl", "w") do |file|
|
|
484
|
+
schema.generate_stream(count: 1_000_000).each do |record|
|
|
485
|
+
file.puts(record.to_json)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Batch Processing
|
|
491
|
+
|
|
492
|
+
```ruby
|
|
493
|
+
# Process in chunks to balance memory/speed
|
|
494
|
+
total = 1_000_000
|
|
495
|
+
batch_size = 10_000
|
|
496
|
+
|
|
497
|
+
(total / batch_size).times do |i|
|
|
498
|
+
batch = schema.generate_many(batch_size, seed: i)
|
|
499
|
+
process_batch(batch)
|
|
500
|
+
batch = nil # Allow GC
|
|
501
|
+
GC.start if i % 10 == 0
|
|
502
|
+
end
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## CI Performance Gates
|
|
508
|
+
|
|
509
|
+
### GitHub Actions Example
|
|
510
|
+
|
|
511
|
+
```yaml
|
|
512
|
+
- name: Performance Regression Test
|
|
513
|
+
run: |
|
|
514
|
+
# Benchmark and check thresholds
|
|
515
|
+
RESULT=$(bundle exec ruby -e "
|
|
516
|
+
require 'synthra'
|
|
517
|
+
require 'benchmark'
|
|
518
|
+
|
|
519
|
+
schema = Synthra.parse('User:\n id: uuid\n name: name')
|
|
520
|
+
time = Benchmark.measure { schema.generate_many(10000) }.real
|
|
521
|
+
|
|
522
|
+
puts time
|
|
523
|
+
")
|
|
524
|
+
|
|
525
|
+
# Fail if > 1 second for 10k records
|
|
526
|
+
if (( $(echo "$RESULT > 1.0" | bc -l) )); then
|
|
527
|
+
echo "Performance regression! 10k records took ${RESULT}s (threshold: 1.0s)"
|
|
528
|
+
exit 1
|
|
529
|
+
fi
|
|
530
|
+
|
|
531
|
+
echo "Performance OK: ${RESULT}s for 10k records"
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Profiling Tools
|
|
537
|
+
|
|
538
|
+
### Ruby Profiler
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
# CPU profiling
|
|
542
|
+
bundle exec ruby -rprofile benchmark/single_record.rb
|
|
543
|
+
|
|
544
|
+
# With ruby-prof gem
|
|
545
|
+
bundle exec ruby -rruby-prof benchmark/single_record.rb
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Memory Profiling
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
# With memory_profiler gem
|
|
552
|
+
bundle exec ruby benchmark/memory_profile.rb
|
|
553
|
+
|
|
554
|
+
# With Valgrind (Linux)
|
|
555
|
+
valgrind --tool=massif bundle exec ruby benchmark/streaming.rb
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Comparison with Alternatives
|
|
561
|
+
|
|
562
|
+
| Tool | 10k Records | 1M Records | Memory | Features |
|
|
563
|
+
|------|-------------|------------|--------|----------|
|
|
564
|
+
| **Synthra Native** | ~3ms | ~250ms | O(1) | DSL, fake-rs, 4M/sec |
|
|
565
|
+
| Synthra Ruby | ~1.5s | ~150s | O(n) | DSL, Faker, streaming |
|
|
566
|
+
| Faker alone | ~200ms | ~20s | O(n) | No DSL, no structure |
|
|
567
|
+
| FactoryBot | ~800ms | ~80s | O(n) | Ruby DSL, no streaming |
|
|
568
|
+
| JSON generators | ~100ms | ~10s | O(n) | No realistic data |
|
|
569
|
+
|
|
570
|
+
### Why Use Synthra?
|
|
571
|
+
|
|
572
|
+
**Native Engine (Recommended for production):**
|
|
573
|
+
- 4-5M records/sec to file
|
|
574
|
+
- Multi-locale support (en, fr, de, ja, zh...)
|
|
575
|
+
- Configurable threads (default: 2)
|
|
576
|
+
- Full faker functionality via fake-rs
|
|
577
|
+
|
|
578
|
+
**Ruby Engine:**
|
|
579
|
+
- Declarative DSL schemas
|
|
580
|
+
- Deterministic output with seeds
|
|
581
|
+
- Cross-schema references
|
|
582
|
+
- Type safety and validation
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Next Steps
|
|
587
|
+
|
|
588
|
+
- [CI/CD Integration](../tech_docs/integration/ci_cd_guide.md)
|
|
589
|
+
- [Configuration Guide](../tech_docs/configuration.md)
|
|
590
|
+
- [Streaming Guide](../tech_docs/api/streaming.md)
|
|
591
|
+
|