mirror of
https://github.com/thead-yocto-mirror/skia
synced 2026-08-23 00:38:54 +02:00
161 lines
4.2 KiB
C
161 lines
4.2 KiB
C
// Copyright 2017 The Wuffs Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// ----------------
|
|
|
|
// This file contains a hand-written C implementation of the Adler32 hash
|
|
// function, based on the code generated by the Wuffs std/zlib implementation.
|
|
// Its purpose is to benchmark different compilers, or different versions of
|
|
// the same compiler family.
|
|
//
|
|
// For example, on a Debian Testing system as of November 2017:
|
|
//
|
|
// $ clang-5.0 -O3 adler32-standalone.c; ./a.out
|
|
// 2311 MiB/s, clang 5.0.0 (tags/RELEASE_500/rc2)
|
|
// $ gcc -O3 adler32-standalone.c; ./a.out
|
|
// 3052 MiB/s, gcc 7.2.1 20171025
|
|
//
|
|
// which suggest that clang's code performs at about 76% the throughput of
|
|
// gcc's. This is filed as https://bugs.llvm.org/show_bug.cgi?id=35567
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
|
|
#define BUFFER_SIZE (1024 * 1024)
|
|
#define ONE_MIBIBYTE (1024 * 1024)
|
|
|
|
// The order matters here. Clang also defines "__GNUC__".
|
|
#if defined(__clang__)
|
|
const char* cc = "clang";
|
|
const char* cc_version = __clang_version__;
|
|
#elif defined(__GNUC__)
|
|
const char* cc = "gcc";
|
|
const char* cc_version = __VERSION__;
|
|
#elif defined(_MSC_VER)
|
|
const char* cc = "cl";
|
|
const char* cc_version = "???";
|
|
#else
|
|
const char* cc = "cc";
|
|
const char* cc_version = "???";
|
|
#endif
|
|
|
|
static uint32_t calculate_hash(uint8_t* x_ptr, size_t x_len) {
|
|
uint32_t s1 = 1;
|
|
uint32_t s2 = 0;
|
|
|
|
while (x_len > 0) {
|
|
uint8_t* prefix_ptr;
|
|
size_t prefix_len;
|
|
if (x_len > 5552) {
|
|
prefix_ptr = x_ptr;
|
|
prefix_len = 5552;
|
|
x_ptr = x_ptr + 5552;
|
|
x_len = x_len - 5552;
|
|
} else {
|
|
prefix_ptr = x_ptr;
|
|
prefix_len = x_len;
|
|
x_ptr = NULL;
|
|
x_len = 0;
|
|
}
|
|
|
|
uint8_t* p = prefix_ptr;
|
|
uint8_t* end0 = prefix_ptr + (prefix_len / 8) * 8;
|
|
while (p < end0) {
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
}
|
|
uint8_t* end1 = prefix_ptr + prefix_len;
|
|
while (p < end1) {
|
|
s1 += ((uint32_t)(*p));
|
|
s2 += s1;
|
|
p++;
|
|
}
|
|
|
|
s1 %= 65521;
|
|
s2 %= 65521;
|
|
}
|
|
return (s2 << 16) | s1;
|
|
}
|
|
|
|
uint8_t buffer[BUFFER_SIZE] = {0};
|
|
|
|
int main(int argc, char** argv) {
|
|
bool nocheck = false;
|
|
int i;
|
|
for (i = 0; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-nocheck")) {
|
|
nocheck = true;
|
|
}
|
|
}
|
|
|
|
struct timeval bench_start_tv;
|
|
gettimeofday(&bench_start_tv, NULL);
|
|
|
|
const int num_reps = 1000;
|
|
|
|
// If changing BUFFER_SIZE, re-calculate this expected value with
|
|
// https://play.golang.org/p/IU2T58P00C
|
|
const uint32_t expected_hash_of_1mib_of_zeroes = 0x00f00001UL;
|
|
|
|
int num_bad = 0;
|
|
for (i = 0; i < num_reps; i++) {
|
|
uint32_t actual_hash = calculate_hash(buffer, BUFFER_SIZE);
|
|
if (!nocheck && (actual_hash != expected_hash_of_1mib_of_zeroes)) {
|
|
num_bad++;
|
|
}
|
|
}
|
|
if (num_bad) {
|
|
printf("num_bad: %d\n", num_bad);
|
|
return 1;
|
|
}
|
|
|
|
struct timeval bench_finish_tv;
|
|
gettimeofday(&bench_finish_tv, NULL);
|
|
|
|
int64_t micros =
|
|
(int64_t)(bench_finish_tv.tv_sec - bench_start_tv.tv_sec) * 1000000 +
|
|
(int64_t)(bench_finish_tv.tv_usec - bench_start_tv.tv_usec);
|
|
int64_t numer = ((int64_t)num_reps) * BUFFER_SIZE * 1000000;
|
|
int64_t denom = micros * ONE_MIBIBYTE;
|
|
int64_t mib_per_s = denom ? numer / denom : 0;
|
|
|
|
printf("%8d MiB/s, %s %s\n", (int)mib_per_s, cc, cc_version);
|
|
return 0;
|
|
}
|