• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

arangodb / velocypack / 3998645281

pending completion
3998645281

Pull #148

github

GitHub
Merge b1e3c924b into 5a28b6413
Pull Request #148: use separate namespace for xxh functions

0 of 5107 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/asm-functions.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
/// DISCLAIMER
3
///
4
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
5
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
6
///
7
/// Licensed under the Apache License, Version 2.0 (the "License");
8
/// you may not use this file except in compliance with the License.
9
/// You may obtain a copy of the License at
10
///
11
///     http://www.apache.org/licenses/LICENSE-2.0
12
///
13
/// Unless required by applicable law or agreed to in writing, software
14
/// distributed under the License is distributed on an "AS IS" BASIS,
15
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
/// See the License for the specific language governing permissions and
17
/// limitations under the License.
18
///
19
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
20
///
21
/// @author Max Neunhoeffer
22
/// @author Jan Steemann
23
////////////////////////////////////////////////////////////////////////////////
24

25
#include <chrono>
26
#include <cstring>
27
#include <iostream>
28

29
#include "asm-functions.h"
30
#include "asm-utf8check.h"
31
#include "velocypack/Utf8Helper.h"
32
#include "velocypack/velocypack-common.h"
33

34
#if VELOCYPACK_ASM_OPTIMIZATIONS == 1
35
#if defined(__SSE4_2__)
36
#include <cpuid.h>
37
#include <x86intrin.h>
38
#elif defined(__aarch64__)
39
#include <sse2neon.h>
40
#endif
41
#endif
42

43
namespace arangodb::velocypack {
44
namespace {
45

46
inline std::size_t JSONStringCopyC(uint8_t* dst, uint8_t const* src,
×
47
                                   std::size_t limit) {
48
  // Copy up to limit uint8_t from src to dst.
49
  // Stop at the first control character or backslash or double quote.
50
  // Report the number of bytes copied. May copy less bytes, for example
51
  // for alignment reasons.
52
  uint8_t const* end = src + limit;
×
53
  while (src < end && *src >= 32 && *src != '\\' && *src != '"') {
×
54
    *dst++ = *src++;
×
55
  }
56
  return limit - (end - src);
×
57
}
58

59
inline std::size_t JSONStringCopyCheckUtf8C(uint8_t* dst, uint8_t const* src,
×
60
                                            std::size_t limit) {
61
  // Copy up to limit uint8_t from src to dst.
62
  // Stop at the first control character or backslash or double quote.
63
  // Also stop at byte with high bit set.
64
  // Report the number of bytes copied. May copy less bytes, for example
65
  // for alignment reasons.
66
  uint8_t const* end = src + limit;
×
67
  while (src < end && *src >= 32 && *src != '\\' && *src != '"' &&
×
68
         *src < 0x80) {
×
69
    *dst++ = *src++;
×
70
  }
71
  return limit - (end - src);
×
72
}
73

74
inline std::size_t JSONSkipWhiteSpaceC(uint8_t const* src, std::size_t limit) {
×
75
  // Skip up to limit uint8_t from src as long as they are whitespace.
76
  // Advance ptr and return the number of skipped bytes.
77
  uint8_t const* end = src + limit;
×
78
  while (src < end &&
×
79
         (*src == ' ' || *src == '\t' || *src == '\n' || *src == '\r')) {
×
80
    src++;
×
81
  }
82
  return limit - (end - src);
×
83
}
84

85
inline bool ValidateUtf8StringC(uint8_t const* src, std::size_t limit) {
×
86
  return Utf8Helper::isValidUtf8(src, static_cast<ValueLength>(limit));
×
87
}
88

89
#if defined(__SSE4_2__) && VELOCYPACK_ASM_OPTIMIZATIONS == 1
90
bool hasSSE42() noexcept {
91
  unsigned int eax, ebx, ecx, edx;
92
  if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
93
    if ((ecx & 0x100000) != 0) {
94
      return true;
95
    }
96
  }
97
  return false;
98
}
99

100
std::size_t JSONStringCopySSE42(uint8_t* dst, uint8_t const* src,
101
                                std::size_t limit) {
102
  alignas(16) static char const ranges[17] =
103
      "\x20\x21\x23\x5b\x5d\xff          ";
104
  //= "\x01\x1f\"\"\\\\\"\"\"\"\"\"\"\"\"\"";
105

106
  __m128i const r = _mm_load_si128(reinterpret_cast<__m128i const*>(ranges));
107
  std::size_t count = 0;
108
  int x = 0;
109
  while (limit >= 16) {
110
    __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
111
    x = _mm_cmpistri(r, /* 6, */ s, /* 16, */
112
                     _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
113
                         _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
114
    if (x < 16) {
115
      memcpy(dst, src, x);
116
      count += x;
117
      return count;
118
    }
119
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), s);
120
    src += 16;
121
    dst += 16;
122
    limit -= 16;
123
    count += 16;
124
  }
125
  if (limit == 0) {
126
    return count;
127
  }
128
  __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
129
  x = _mm_cmpistri(r, /* 6, */ s, /* limit, */
130
                   _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
131
                       _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
132
  if (x > static_cast<int>(limit)) {
133
    x = static_cast<int>(limit);
134
  }
135
  memcpy(dst, src, x);
136
  count += x;
137
  return count;
138
}
139

140
std::size_t JSONStringCopyCheckUtf8SSE42(uint8_t* dst, uint8_t const* src,
141
                                         std::size_t limit) {
142
  alignas(16) static unsigned char const ranges[17] =
143
      "\x20\x21\x23\x5b\x5d\x7f          ";
144
  //= "\x01\x1f\x80\xff\"\"\\\\\"\"\"\"\"\"\"\"";
145
  __m128i const r = _mm_load_si128(reinterpret_cast<__m128i const*>(ranges));
146
  std::size_t count = 0;
147
  int x = 0;
148
  while (limit >= 16) {
149
    __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
150
    x = _mm_cmpistri(r, /* 8, */ s, /* 16, */
151
                     _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
152
                         _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
153
    if (x < 16) {
154
      memcpy(dst, src, x);
155
      count += x;
156
      return count;
157
    }
158
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), s);
159
    src += 16;
160
    dst += 16;
161
    limit -= 16;
162
    count += 16;
163
  }
164
  if (limit == 0) {
165
    return count;
166
  }
167
  __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(src));
168
  x = _mm_cmpistri(r, /* 8, */ s, /* limit, */
169
                   _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
170
                       _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
171
  if (x > static_cast<int>(limit)) {
172
    x = static_cast<int>(limit);
173
  }
174
  memcpy(dst, src, x);
175
  count += x;
176
  return count;
177
}
178

179
std::size_t JSONSkipWhiteSpaceSSE42(uint8_t const* ptr, std::size_t limit) {
180
  alignas(16) static char const white[17] = " \t\n\r            ";
181
  __m128i const w = _mm_load_si128(reinterpret_cast<__m128i const*>(white));
182
  std::size_t count = 0;
183
  int x = 0;
184
  while (limit >= 16) {
185
    __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(ptr));
186
    x = _mm_cmpistri(w, /* 4, */ s, /*  16, */
187
                     _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY |
188
                         _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
189
    if (x < 16) {
190
      count += x;
191
      return count;
192
    }
193
    ptr += 16;
194
    limit -= 16;
195
    count += 16;
196
  }
197
  if (limit == 0) {
198
    return count;
199
  }
200
  __m128i const s = _mm_loadu_si128(reinterpret_cast<__m128i const*>(ptr));
201
  x = _mm_cmpistri(w, /* 4, */ s, /* limit, */
202
                   _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY |
203
                       _SIDD_NEGATIVE_POLARITY | _SIDD_LEAST_SIGNIFICANT);
204
  if (static_cast<std::size_t>(x) > limit) {
205
    x = static_cast<int>(limit);
206
  }
207
  count += x;
208
  return count;
209
}
210

211
#endif
212
#if VELOCYPACK_ASM_OPTIMIZATIONS == 1
213

214
bool ValidateUtf8StringSSE42(uint8_t const* src, std::size_t len) {
215
  if (len >= 16) {
216
    return validate_utf8_fast_sse42(src, len);
217
  }
218
  return Utf8Helper::isValidUtf8(src, len);
219
}
220

221
#endif
222
#if defined(__AVX2__) && VELOCYPACK_ASM_OPTIMIZATIONS == 1
223

224
bool hasAVX2() noexcept {
225
  unsigned int eax, ebx, ecx, edx;
226
  if (__get_cpuid(7, &eax, &ebx, &ecx, &edx)) {
227
    if ((ebx & bit_AVX2) != 0) {
228
      return true;
229
    }
230
  }
231
  return false;
232
}
233

234
bool ValidateUtf8StringAVX(uint8_t const* src, std::size_t len) {
235
  if (len >= 32) {
236
    return validate_utf8_fast_avx(src, len);
237
  }
238
  return Utf8Helper::isValidUtf8(src, len);
239
}
240

241
#endif
242

243
struct EnableNative {
244
  EnableNative() noexcept { enableNativeStringFunctions(); }
×
245
};
246

247
[[maybe_unused]] EnableNative const init;
248

249
}  // namespace
250

251
std::size_t (*JSONStringCopy)(uint8_t*, uint8_t const*,
252
                              std::size_t) = JSONStringCopyC;
253

254
std::size_t (*JSONStringCopyCheckUtf8)(uint8_t*, uint8_t const*,
255
                                       std::size_t) = JSONStringCopyCheckUtf8C;
256

257
std::size_t (*JSONSkipWhiteSpace)(uint8_t const*,
258
                                  std::size_t) = JSONSkipWhiteSpaceC;
259

260
bool (*ValidateUtf8String)(uint8_t const*, std::size_t) = ValidateUtf8StringC;
261

262
void enableNativeStringFunctions() noexcept {
×
263
  enableBuiltinStringFunctions();
×
264
#if defined(__SSE4_2__) && VELOCYPACK_ASM_OPTIMIZATIONS == 1
265
  if (hasSSE42()) {
266
    JSONStringCopy = JSONStringCopySSE42;
267
    JSONStringCopyCheckUtf8 = JSONStringCopyCheckUtf8SSE42;
268
    JSONSkipWhiteSpace = JSONSkipWhiteSpaceSSE42;
269
    ValidateUtf8String = ValidateUtf8StringSSE42;
270
  }
271
#elif defined(__aarch64__) && VELOCYPACK_ASM_OPTIMIZATIONS == 1
272
  ValidateUtf8String = ValidateUtf8StringSSE42;
273
#endif
274
#if defined(__AVX2__) && VELOCYPACK_ASM_OPTIMIZATIONS == 1
275
  if (hasAVX2()) {
276
    ValidateUtf8String = ValidateUtf8StringAVX;
277
  }
278
#endif
279
}
×
280

281
void enableBuiltinStringFunctions() noexcept {
×
282
  JSONStringCopy = JSONStringCopyC;
×
283
  JSONStringCopyCheckUtf8 = JSONStringCopyCheckUtf8C;
×
284
  JSONSkipWhiteSpace = JSONSkipWhiteSpaceC;
×
285
  ValidateUtf8String = ValidateUtf8StringC;
×
286
}
×
287

288
}  // namespace arangodb::velocypack
289

290
#if defined(COMPILE_VELOCYPACK_ASM_UNITTESTS)
291

292
int testPositions[] = {
293
    0,   1,   2,   3,   4,   5,   6,    7,    8,    9,    10,   11,   12,  13,
294
    14,  15,  16,  23,  31,  32,  67,   103,  178,  210,  234,  247,  254, 255,
295
    -1,  -2,  -3,  -4,  -5,  -6,  -7,   -8,   -9,   -10,  -11,  -12,  -13, -14,
296
    -15, -16, -23, -31, -32, -67, -103, -178, -210, -234, -247, -254, -255};
297

298
using namespace arangodb::velocypack;
299

300
void TestStringCopyCorrectness(uint8_t* src, uint8_t* dst, std::size_t size) {
301
  std::size_t copied;
302

303
  std::cout << "Performing correctness tests..." << std::endl;
304

305
  auto start = std::chrono::high_resolution_clock::now();
306

307
  for (std::size_t salign = 0; salign < 16; salign++) {
308
    src += salign;
309
    for (std::size_t dalign = 0; dalign < 16; dalign++) {
310
      dst += dalign;
311
      for (std::size_t i = 0;
312
           i < static_cast<int>(sizeof(testPositions) / sizeof(int)); i++) {
313
        uint8_t merk;
314
        int off = testPositions[i];
315
        std::size_t pos;
316
        if (off >= 0) {
317
          pos = off;
318
        } else {
319
          pos = size - static_cast<std::size_t>(-off);
320
        }
321
        if (pos >= size) {
322
          continue;
323
        }
324

325
        // Test a quote character:
326
        merk = src[pos];
327
        src[pos] = '"';
328
        copied = JSONStringCopy(dst, src, size);
329
        if (copied != pos || memcmp(dst, src, copied) != 0) {
330
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
331
                    << pos << " " << copied << std::endl;
332
        }
333
        src[pos] = merk;
334

335
        // Test a backslash character:
336
        src[pos] = '\\';
337
        copied = JSONStringCopy(dst, src, size);
338
        if (copied != pos || memcmp(dst, src, copied) != 0) {
339
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
340
                    << pos << " " << copied << std::endl;
341
        }
342
        src[pos] = merk;
343

344
        // Test a 0 character:
345
        src[pos] = 1;
346
        copied = JSONStringCopy(dst, src, size);
347
        if (copied != pos || memcmp(dst, src, copied) != 0) {
348
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
349
                    << pos << " " << copied << std::endl;
350
        }
351
        src[pos] = merk;
352

353
        // Test a control character:
354
        src[pos] = 31;
355
        copied = JSONStringCopy(dst, src, size);
356
        if (copied != pos || memcmp(dst, src, copied) != 0) {
357
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
358
                    << pos << " " << copied << std::endl;
359
        }
360
        src[pos] = merk;
361
      }
362
      dst -= dalign;
363
    }
364
    src -= salign;
365
  }
366

367
  auto now = std::chrono::high_resolution_clock::now();
368
  std::chrono::duration<double> totalTime =
369
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
370
  std::cout << "Tests took altogether " << totalTime.count() << " seconds."
371
            << std::endl;
372
}
373

374
void TestStringCopyCorrectnessCheckUtf8(uint8_t* src, uint8_t* dst,
375
                                        std::size_t size) {
376
  std::size_t copied;
377

378
  std::cout << "Performing correctness tests (check UTF8)..." << std::endl;
379

380
  auto start = std::chrono::high_resolution_clock::now();
381

382
  for (int salign = 0; salign < 16; salign++) {
383
    src += salign;
384
    for (int dalign = 0; dalign < 16; dalign++) {
385
      dst += dalign;
386
      for (int i = 0; i < static_cast<int>(sizeof(testPositions) / sizeof(int));
387
           i++) {
388
        uint8_t merk;
389
        int off = testPositions[i];
390
        std::size_t pos;
391
        if (off >= 0) {
392
          pos = off;
393
        } else {
394
          pos = size - static_cast<std::size_t>(-off);
395
        }
396
        if (pos >= size) {
397
          continue;
398
        }
399

400
        // Test a quote character:
401
        merk = src[pos];
402
        src[pos] = '"';
403
        copied = JSONStringCopyCheckUtf8(dst, src, size);
404
        if (copied != pos || memcmp(dst, src, copied) != 0) {
405
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
406
                    << pos << " " << copied << std::endl;
407
        }
408
        src[pos] = merk;
409

410
        // Test a backslash character:
411
        src[pos] = '\\';
412
        copied = JSONStringCopyCheckUtf8(dst, src, size);
413
        if (copied != pos || memcmp(dst, src, copied) != 0) {
414
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
415
                    << pos << " " << copied << std::endl;
416
        }
417
        src[pos] = merk;
418

419
        // Test a 0 character:
420
        src[pos] = 1;
421
        copied = JSONStringCopyCheckUtf8(dst, src, size);
422
        if (copied != pos || memcmp(dst, src, copied) != 0) {
423
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
424
                    << pos << " " << copied << std::endl;
425
        }
426
        src[pos] = merk;
427

428
        // Test a control character:
429
        src[pos] = 31;
430
        copied = JSONStringCopyCheckUtf8(dst, src, size);
431
        if (copied != pos || memcmp(dst, src, copied) != 0) {
432
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
433
                    << pos << " " << copied << std::endl;
434
        }
435
        src[pos] = merk;
436

437
        // Test a high bitcharacter:
438
        src[pos] = 0x80;
439
        copied = JSONStringCopyCheckUtf8(dst, src, size);
440
        if (copied != pos || memcmp(dst, src, copied) != 0) {
441
          std::cout << "Error: " << salign << " " << dalign << " " << i << " "
442
                    << pos << " " << copied << std::endl;
443
        }
444
        src[pos] = merk;
445
      }
446
      dst -= dalign;
447
    }
448
    src -= salign;
449
  }
450

451
  auto now = std::chrono::high_resolution_clock::now();
452
  std::chrono::duration<double> totalTime =
453
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
454
  std::cout << "Tests took altogether " << totalTime.count() << " seconds."
455
            << std::endl;
456
}
457

458
void TestSkipWhiteSpaceCorrectness(uint8_t* src, std::size_t size) {
459
  std::size_t copied;
460

461
  std::cout << "Performing correctness tests for whitespace skipping..."
462
            << std::endl;
463

464
  auto start = std::chrono::high_resolution_clock::now();
465

466
  for (int salign = 0; salign < 16; salign++) {
467
    src += salign;
468
    for (int i = 0; i < static_cast<int>(sizeof(testPositions) / sizeof(int));
469
         i++) {
470
      uint8_t merk;
471
      int off = testPositions[i];
472
      std::size_t pos;
473
      if (off >= 0) {
474
        pos = off;
475
      } else {
476
        pos = size - static_cast<std::size_t>(-off);
477
      }
478
      if (pos >= size) {
479
        continue;
480
      }
481

482
      // Test a non-whitespace character:
483
      merk = src[pos];
484
      src[pos] = 'x';
485
      copied = JSONSkipWhiteSpace(src, size);
486
      if (copied != pos) {
487
        std::cout << "Error: " << salign << " " << i << " " << pos << " "
488
                  << copied << std::endl;
489
      }
490
      src[pos] = merk;
491
    }
492
    src -= salign;
493
  }
494

495
  auto now = std::chrono::high_resolution_clock::now();
496
  std::chrono::duration<double> totalTime =
497
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
498
  std::cout << "Whitespace tests took altogether " << totalTime.count()
499
            << " seconds." << std::endl;
500
}
501

502
void RaceStringCopy(uint8_t* dst, uint8_t* src, std::size_t size, int repeat,
503
                    uint64_t& akku) {
504
  std::size_t copied;
505

506
  std::cout << "\nNow racing for the repeated full string, "
507
            << "first target aligned...\n"
508
            << std::endl;
509

510
  src[size] = 0;
511
  auto start = std::chrono::high_resolution_clock::now();
512
  for (int j = 0; j < repeat; j++) {
513
    copied = JSONStringCopy(dst, src, size);
514
    akku = akku * 13 + copied;
515
  }
516
  auto now = std::chrono::high_resolution_clock::now();
517
  src[size] = 'a' + (size % 26);
518

519
  auto totalTime =
520
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
521

522
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
523
            << std::endl;
524
  std::cout << "Time to copy string of length " << size
525
            << " on average is: " << totalTime.count() / repeat << "."
526
            << std::endl;
527
  std::cout << "Bytes copied per second: "
528
            << (double)size * (double)repeat / totalTime.count() << std::endl;
529

530
  std::cout << "\nNow racing for the repeated full string, "
531
            << "now unaligned target...\n"
532
            << std::endl;
533

534
  dst++;
535
  start = std::chrono::high_resolution_clock::now();
536
  for (int j = 0; j < repeat; j++) {
537
    copied = JSONStringCopy(dst, src, size);
538
    akku = akku * 13 + copied;
539
  }
540
  now = std::chrono::high_resolution_clock::now();
541

542
  totalTime =
543
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
544

545
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
546
            << std::endl;
547
  std::cout << "Time to copy string of length " << size
548
            << " on average is: " << totalTime.count() / repeat << "."
549
            << std::endl;
550
  std::cout << "Bytes copied per second: "
551
            << (double)size * (double)repeat / totalTime.count() << std::endl;
552
}
553

554
void RaceStringCopyCheckUtf8(uint8_t* dst, uint8_t* src, std::size_t size,
555
                             int repeat, uint64_t& akku) {
556
  std::size_t copied;
557

558
  std::cout << "\nNow racing for the repeated (check UTF8) full string, "
559
            << "first target aligned...\n"
560
            << std::endl;
561

562
  src[size] = 0;
563
  auto start = std::chrono::high_resolution_clock::now();
564
  for (int j = 0; j < repeat; j++) {
565
    copied = JSONStringCopy(dst, src, size);
566
    akku = akku * 13 + copied;
567
  }
568
  auto now = std::chrono::high_resolution_clock::now();
569
  src[size] = 'a' + (size % 26);
570

571
  auto totalTime =
572
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
573

574
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
575
            << std::endl;
576
  std::cout << "Time to copy string of length " << size
577
            << " on average is: " << totalTime.count() / repeat << "."
578
            << std::endl;
579
  std::cout << "Bytes copied per second: "
580
            << (double)size * (double)repeat / totalTime.count() << std::endl;
581

582
  std::cout
583
      << "\nNow racing for the repeated full string, now unaligned target...\n"
584
      << std::endl;
585

586
  dst++;
587
  start = std::chrono::high_resolution_clock::now();
588
  for (int j = 0; j < repeat; j++) {
589
    copied = JSONStringCopy(dst, src, size);
590
    akku = akku * 13 + copied;
591
  }
592
  now = std::chrono::high_resolution_clock::now();
593
  dst--;
594

595
  totalTime =
596
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
597

598
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
599
            << std::endl;
600
  std::cout << "Time to copy string of length " << size
601
            << " on average is: " << totalTime.count() / repeat << "."
602
            << std::endl;
603
  std::cout << "Bytes copied per second: "
604
            << (double)size * (double)repeat / totalTime.count() << std::endl;
605

606
  std::cout << "\nNow comparing with strcpy...\n" << std::endl;
607

608
  start = std::chrono::high_resolution_clock::now();
609
  for (int j = 0; j < repeat; j++) {
610
    // strcpy((char*) dst, (char*) src);
611
    memcpy((char*)dst, (char*)src, size);
612
  }
613
  now = std::chrono::high_resolution_clock::now();
614

615
  totalTime =
616
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
617

618
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
619
            << std::endl;
620
  std::cout << "Time to copy string of length " << size
621
            << " on average is: " << totalTime.count() / repeat << "."
622
            << std::endl;
623
  std::cout << "Bytes copied per second: "
624
            << (double)size * (double)repeat / totalTime.count() << std::endl;
625
}
626

627
void RaceSkipWhiteSpace(uint8_t* src, std::size_t size, int repeat,
628
                        uint64_t& akku) {
629
  std::size_t copied;
630

631
  std::cout << "\nNow racing for the repeated full string...\n" << std::endl;
632

633
  auto start = std::chrono::high_resolution_clock::now();
634
  akku = 0;
635
  src[size] = 0;
636
  for (int j = 0; j < repeat; j++) {
637
    copied = JSONSkipWhiteSpace(src, size);
638
    akku = akku * 13 + copied;
639
  }
640
  auto now = std::chrono::high_resolution_clock::now();
641

642
  auto totalTime =
643
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
644

645
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
646
            << std::endl;
647
  std::cout << "Time to skip white string of length " << size
648
            << " on average is: " << totalTime.count() / repeat << "."
649
            << std::endl;
650
  std::cout << "Bytes skipped per second: "
651
            << (double)size * (double)repeat / totalTime.count() << std::endl;
652

653
  std::cout << "\nNow comparing with strlen...\n" << std::endl;
654

655
  start = std::chrono::high_resolution_clock::now();
656
  for (int j = 0; j < repeat; j++) {
657
    copied = strlen((char*)src);
658
    // Fake activity for the compiler:
659
    src[0] = (j & 0xf) + 1;
660
    akku = akku * 13 + copied;
661
  }
662
  now = std::chrono::high_resolution_clock::now();
663

664
  totalTime =
665
      std::chrono::duration_cast<std::chrono::duration<double>>(now - start);
666

667
  std::cout << "Race took altogether " << totalTime.count() << " seconds."
668
            << std::endl;
669
  std::cout << "Time to strlen string of length " << size
670
            << " on average is: " << totalTime.count() / repeat << "."
671
            << std::endl;
672
  std::cout << "Bytes scanned per second: "
673
            << (double)size * (double)repeat / totalTime.count() << std::endl;
674
}
675

676
int main(int argc, char* argv[]) {
677
  if (argc < 4) {
678
    std::cout << "Usage: " << argv[0] << " SIZE REPEAT CORRECTNESS"
679
              << std::endl;
680
    return 0;
681
  }
682

683
  std::size_t size = atol(argv[1]);
684
  int repeat = atoi(argv[2]);
685
  int docorrectness = atoi(argv[3]);
686
  uint64_t akku = 0;
687
  std::cout << "Size: " << size << std::endl;
688
  std::cout << "Repeat:" << repeat << std::endl;
689

690
  uint8_t* src = new uint8_t[size + 17 + 16];
691
  uint8_t* dst = new uint8_t[size + 17];
692
  std::cout << "Src pointer: " << (void*)src << std::endl;
693
  std::cout << "Dst pointer: " << (void*)dst << std::endl;
694
  for (std::size_t i = 0; i < size + 16; i++) {
695
    src[i] = 'a' + (i % 26);
696
  }
697
  src[size + 16] = 0;
698

699
  if (docorrectness > 0) {
700
    TestStringCopyCorrectness(src, dst, size);
701
  }
702

703
  RaceStringCopy(dst, src, size, repeat, akku);
704

705
  if (docorrectness > 0) {
706
    TestStringCopyCorrectnessCheckUtf8(src, dst, size);
707
  }
708

709
  RaceStringCopyCheckUtf8(dst, src, size, repeat, akku);
710

711
  std::cout << "\n\n\nNOW WHITESPACE SKIPPING\n" << std::endl;
712

713
  // Now do the whitespace skipping tests/measurements:
714
  static char const whitetab[17] = "       \t   \n   \r";
715
  for (std::size_t i = 0; i < size + 16; i++) {
716
    src[i] = whitetab[i % 16];
717
  }
718
  src[size + 16] = 0;
719

720
  if (docorrectness > 0) {
721
    TestSkipWhiteSpaceCorrectness(src, size);
722
  }
723

724
  RaceSkipWhiteSpace(src, size, repeat, akku);
725

726
  std::cout << "\n\n\nAkku (please ignore):" << akku << std::endl;
727
  std::cout << "\n\n\nGuck (please ignore): " << dst[100] << std::endl;
728

729
  delete[] src;
730
  delete[] dst;
731
  return 0;
732
}
733

734
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc