Skip to content

Benchmarks

Pseudata’s pseudo-arrays provide constant-time access to any element, regardless of its position in the sequence. Unlike traditional arrays that must allocate memory or sequential generators that must iterate through all previous elements, pseudo-arrays compute each element independently in O(1)O(1) time.

This page demonstrates real-world performance characteristics across different array types and access patterns.

The following benchmarks measure the time to access individual elements at various positions, from the first element to the trillionth (24012^{40}-1). All tests were performed on an average laptop.

UserArray

UserArray.At(i) in Go

iiTTΔT\Delta T
005.551μs5.551\mu s
115.68μs5.68\mu s0.129μs0.129\mu s
282^{8}5.75μs5.75\mu s0.199μs0.199\mu s
2162^{16}6.292μs6.292\mu s0.741μs0.741\mu s
2322^{32}7.073μs7.073\mu s1.522μs1.522\mu s
24012^{40}-17.973μs7.973\mu s2.422μs2.422\mu s

AddressArray

AddressArray.At(i) in Go

iiTTΔT\Delta T
002.793μs2.793\mu s
112.866μs2.866\mu s0.073μs0.073\mu s
282^{8}2.893μs2.893\mu s0.100μs0.100\mu s
2162^{16}2.988μs2.988\mu s0.195μs0.195\mu s
2322^{32}3.516μs3.516\mu s0.723μs0.723\mu s
24012^{40}-13.941μs3.941\mu s1.148μs1.148\mu s

The tables above are representative examples demonstrating access time characteristics—Pseudata includes pseudo-arrays for many more entity types beyond User and Address.

As demonstrated above, access time remains practically constant—whether retrieving the 1st element or the trillionth (24012^{40}-1). This validates true O(1)O(1) behavior: index position has negligible impact on performance, enabling instant access to any element in a trillion-element dataset.

The ΔTΔT column shows the seeking time—the overhead of advancing the PCG32 generator to the target index. This seeking operation is technically O(logn)O(\log n) due to the generator’s advance() method, which uses binary exponentiation to jump to any position.

Total access time = Seeking time (ΔTΔT) + Generation time

  • Seeking time (ΔTΔT): O(logn)O(\log n) but grows extremely slowly (measured in nanoseconds/microseconds)
  • Generation time: O(1)O(1) and remains constant regardless of index—this is the bulk of the access time

The O(logn)O(\log n) seeking factor is so small compared to the constant generation time that practical access time is effectively O(1)O(1). Even at index 24012^{40}-1 (over 1 trillion), seeking adds only a negligible amount for real-world use cases.

Put this in perspective: While Pseudata’s ΔTΔT seeking overhead is measured in microseconds (millionths of a second), traditional sequential generators would take seconds or tens of seconds to iterate through millions of records—a difference of six orders of magnitude.

The slight variations in access time are due to:

  • Data complexity: UserArray generates more fields than AddressArray
  • Seeking overhead: Logarithmic growth, but imperceptible in practice (nanoseconds to microseconds)
  • CPU cache effects: Minor variations from system state
  • String operations: Name generation involves more allocations than simple numeric fields
  • No memory overhead: Accessing element 1 trillion requires the same memory as accessing element 1
  • No sequential dependency: Jump directly to any index without computing intermediate values
  • Predictable performance: Access time is determined by entity complexity, not position
  • Scalable testing: Load test with billions of records without infrastructure costs

All benchmarks use Go’s standard testing.B benchmark framework with the following settings:

  • Iterations: Automatically determined by Go benchmark runner for statistical significance
  • Warmup: Initial iterations excluded from timing
  • System: Standard development laptop (no dedicated benchmark hardware)
  • Isolation: Each benchmark runs independently

To understand the practical impact of O(1)O(1) access, consider how Pseudata compares to traditional data generation approaches.

Traditional faker libraries must iterate through all previous elements:

# To access element 1,000,000 with traditional faker
faker.seed(42)
for i in range(1_000_000): # Must iterate O(n)
user = faker.person()

With Pseudata:

# Direct access - O(1)
users = UserArray(42)
user = users.at(1_000_000) # Instant O(1) access

Pre-allocated arrays require memory proportional to size:

# Traditional array for 1 million users
users = [generate_user(i) for i in range(1_000_000)] # High memory usage

With Pseudata:

# Pseudo-array for 1 trillion users
users = UserArray(42)
user = users.at(1_000_000_000_000) # No memory overhead