|
// Written by retoor@molodetz.nl
|
|
|
|
// This source code provides benchmarking functions for different string manipulation, comparison, and mathematical operations. It evaluates
|
|
// the performance of various implementations of operations such as formatting numbers, starting and ending string matching, string moving,
|
|
// and mathematical operations like addition and subtraction. The results are printed, showing total execution time and number of operations
|
|
// performed.
|
|
|
|
// This program uses custom libraries like rbench for benchmarking, rtest for assertions, rtree for handling tree structures, rhashtable for
|
|
// hash table operations, and rtime for time-related operations. External C standard library functions are also used.
|
|
|
|
// MIT License
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
#include "rbench.h"
|
|
#include "rtest.h"
|
|
#include "rtree.h"
|
|
#include "rhashtable.h"
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include "rtime.h"
|
|
|
|
char *format_number_retoor(long lnumber) {
|
|
static char formatted[1024];
|
|
char number[1024];
|
|
sprintf(number, "%ld", lnumber);
|
|
size_t len = strlen(number);
|
|
int comma_count = len / 3;
|
|
int count = 0;
|
|
int offset = 0;
|
|
formatted[comma_count + len] = 0;
|
|
for (int i = len + comma_count; i > 0; i--) {
|
|
formatted[i - offset] = number[i - comma_count];
|
|
if (count == 3) {
|
|
count = 0;
|
|
offset++;
|
|
if (i > 1) {
|
|
formatted[i - offset] = '.';
|
|
}
|
|
}
|
|
count++;
|
|
}
|
|
return formatted;
|
|
}
|
|
|
|
char *format_number_yurii(long long num) {
|
|
static char buf[1024];
|
|
char *buff = buf;
|
|
int isneg = num < 0;
|
|
if (isneg)
|
|
num = -num;
|
|
long long rev = num;
|
|
size_t count;
|
|
for (count = 0; num; count++, num /= 10)
|
|
rev = rev * 10 + num % 10;
|
|
count += (count - 1) / 3;
|
|
|
|
if (isneg)
|
|
*buff++ = '-';
|
|
for (size_t i = 0; i < count; i++) {
|
|
if ((count - i) % 4 == 0) {
|
|
*buff++ = '.';
|
|
} else {
|
|
*buff++ = (rev % 10 + '0');
|
|
rev /= 10;
|
|
}
|
|
}
|
|
*buff = '\0';
|
|
return buf;
|
|
}
|
|
|
|
char *format_number_gpt(long lnumber) {
|
|
static char formatted[1024];
|
|
char number[1024];
|
|
sprintf(number, "%ld", lnumber);
|
|
int len = strlen(number);
|
|
int commas_needed = (len - 1) / 3;
|
|
int new_len = len + commas_needed;
|
|
formatted[new_len] = '\0';
|
|
int i = len - 1;
|
|
int j = new_len - 1;
|
|
int count = 0;
|
|
while (i >= 0) {
|
|
if (count == 3) {
|
|
formatted[j--] = '.';
|
|
count = 0;
|
|
}
|
|
formatted[j--] = number[i--];
|
|
count++;
|
|
}
|
|
return formatted;
|
|
}
|
|
|
|
int rstrcmp(char *l, char *r) {
|
|
while (*l && *l == *r) {
|
|
l++;
|
|
r++;
|
|
}
|
|
return *l - *r;
|
|
}
|
|
|
|
int strcmp_gpt(const char *str1, const char *str2) {
|
|
while (*str1 && (*str1 == *str2)) {
|
|
str1++;
|
|
str2++;
|
|
}
|
|
return *(unsigned char *)str1 - *(unsigned char *)str2;
|
|
}
|
|
|
|
int strcmp_clib(const char *p1, const char *p2) {
|
|
register const unsigned char *s1 = (const unsigned char *)p1;
|
|
register const unsigned char *s2 = (const unsigned char *)p2;
|
|
unsigned c1, c2;
|
|
do {
|
|
c1 = (unsigned char)*s1++;
|
|
c2 = (unsigned char)*s2++;
|
|
if (c1 == '\0')
|
|
return c1 - c2;
|
|
} while (c1 == c2);
|
|
return c1 - c2;
|
|
}
|
|
|
|
void bench_rstrcmp(void *arg1, void *arg2) { __attribute__((unused)) int res = rstrcmp(arg1, arg2); }
|
|
void bench_cstrcmp(void *arg1, void *arg2) { __attribute__((unused)) int res = strcmp(arg1, arg2); }
|
|
|
|
bool bench_starts_with_r(const char *s1, const char *s2) { return rstrstartswith(s1, s2); }
|
|
bool bench_ends_with_r(const char *s1, const char *s2) { return rstrendswith(s1, s2); }
|
|
|
|
bool bench_starts_with_gpt(const char *str, const char *prefix) {
|
|
while (*prefix) {
|
|
if (*str != *prefix) {
|
|
return false;
|
|
}
|
|
str++;
|
|
prefix++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int bench_starts_with_yurii(const char *str, const char *start) {
|
|
if (str == NULL)
|
|
return start == NULL;
|
|
if (str == start || start == NULL || *start == '\0')
|
|
return 1;
|
|
return strncmp(str, start, strlen(start)) == 0;
|
|
}
|
|
|
|
bool bench_ends_with_gpt(const char *str, const char *suffix) {
|
|
size_t str_len = strlen(str);
|
|
size_t suffix_len = strlen(suffix);
|
|
if (suffix_len > str_len) {
|
|
return false;
|
|
}
|
|
const char *str_end = str + str_len - suffix_len;
|
|
while (*suffix) {
|
|
if (*str_end != *suffix) {
|
|
return false;
|
|
}
|
|
str_end++;
|
|
suffix++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int bench_ends_with_yurii(const char *str, const char *end) {
|
|
if (str == NULL)
|
|
return end == NULL;
|
|
if (str == end || end == NULL || *end == '\0')
|
|
return 1;
|
|
size_t end_len = strlen(end);
|
|
return strncmp(str + (strlen(str) - end_len), end, end_len) == 0;
|
|
}
|
|
|
|
void plus(int v1, int v2) { __attribute__((unused)) int v3 = v1 + v2; }
|
|
void min(int v1, int v2) { __attribute__((unused)) int v3 = v2 - v1; }
|
|
|
|
void bench_rstrmove_r() {
|
|
char to_move_1[] = "abc?defgaa";
|
|
rstrmove2(to_move_1, 3, 5, 0);
|
|
rasserts(!strcmp(to_move_1, "?defgabcaa"));
|
|
char to_move_2[] = "?defgabcaa";
|
|
rstrmove2(to_move_2, 0, 5, 3);
|
|
rasserts(!strcmp(to_move_2, "abc?defgaa"));
|
|
char to_move_3[] = "?defgabcaa";
|
|
rstrmove2(to_move_3, 0, 5, 6);
|
|
rasserts(!strcmp(to_move_3, "abcaa?defg"));
|
|
}
|
|
|
|
void bench_rstrmove_gpt() {
|
|
char to_move_1[] = "abc?defgaa";
|
|
rstrmove(to_move_1, 3, 5, 0);
|
|
rasserts(!strcmp(to_move_1, "?defgabcaa"));
|
|
char to_move_2[] = "?defgabcaa";
|
|
rstrmove(to_move_2, 0, 5, 2);
|
|
char to_move_3[] = "?defgabcaa";
|
|
rstrmove(to_move_3, 0, 5, 7);
|
|
rasserts(!strcmp(to_move_3, "abc?defgaa"));
|
|
}
|
|
|
|
void rbench_table_rtree() {
|
|
rtree_t *tree = (rtree_t *)rbf->data;
|
|
if (rbf->first) {
|
|
tree = rtree_new();
|
|
rbf->data = (void *)tree;
|
|
}
|
|
for (int i = 0; i < 1; i++) {
|
|
char *key = rgenerate_key();
|
|
rtree_set(tree, key, key);
|
|
rasserts(!strcmp(rtree_get(tree, key), key));
|
|
}
|
|
if (rbf->last)
|
|
rtree_free(rbf->data);
|
|
}
|
|
|
|
void rbench_table_rhashtable() {
|
|
for (int i = 0; i < 1; i++) {
|
|
char *key = rgenerate_key();
|
|
rset(key, key);
|
|
rasserts(!strcmp(rget(key), key));
|
|
}
|
|
}
|
|
|
|
nsecs_t total_execution_time = 0;
|
|
long total_times = 0;
|
|
bool show_progress = 1;
|
|
|
|
void bench_format_number(long times, long number) {
|
|
rbench_t *r;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r = rbench_new();
|
|
r->show_progress = show_progress;
|
|
r->add_function(r, "number_format", "retoor", format_number_retoor);
|
|
r->add_function(r, "number_format", "yurii", format_number_yurii);
|
|
r->add_function(r, "number_format", "gpt", format_number_gpt);
|
|
r->execute1(r, times, (void *)number);
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_table(long times) {
|
|
rbench_t *r;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r = rbench_new();
|
|
r->show_progress = show_progress;
|
|
r->add_function(r, "rtree", "retoor", rbench_table_rtree);
|
|
r->add_function(r, "hashtable", "k*r", rbench_table_rhashtable);
|
|
r->execute(r, times);
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_rstrmove(long times) {
|
|
rbench_t *r;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r = rbench_new();
|
|
r->show_progress = show_progress;
|
|
r->add_function(r, "rstrmove2", "retoor", bench_rstrmove_r);
|
|
r->add_function(r, "rstrmove", "gpt", bench_rstrmove_gpt);
|
|
r->execute(r, times);
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_math(long times) {
|
|
rbench_t *r = rbench_new();
|
|
r->show_progress = show_progress;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r->add_function(r, "plus", "math", plus);
|
|
r->add_function(r, "min", "math", min);
|
|
r->execute2(r, times, (void *)5, (void *)5);
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_strcmp(long times) {
|
|
rbench_t *r = rbench_new();
|
|
r->stdout = false;
|
|
r->show_progress = show_progress;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r->add_function(r, "strcmp_clib", "scmp", strcmp_clib);
|
|
r->add_function(r, "strcmp", "scmp", strcmp);
|
|
r->add_function(r, "rstrcmp", "scmp", rstrcmp);
|
|
r->add_function(r, "strcmp_gpt", "scmp", strcmp_gpt);
|
|
r->execute2(r, times, "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void printf_strcat() {
|
|
char buffer[1000] = {0};
|
|
for (int i = 0; i < 1000; i++) {
|
|
strcat(buffer, "a");
|
|
}
|
|
printf("%s", buffer);
|
|
}
|
|
|
|
void printf_raw() {
|
|
for (int i = 0; i < 1000; i++) {
|
|
printf("%s", "a");
|
|
}
|
|
}
|
|
|
|
void bench_sprintf(long times) {
|
|
rbench_t *r = rbench_new();
|
|
r->stdout = false;
|
|
r->show_progress = show_progress;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r->add_function(r, "strcat", "buffered", printf_strcat);
|
|
r->add_function(r, "printf", "raw", printf_raw);
|
|
r->execute(r, times);
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_startswith(long times) {
|
|
rbench_t *r = rbench_new();
|
|
r->stdout = false;
|
|
r->show_progress = show_progress;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r->add_function(r, "startswith", "retoor", bench_starts_with_r);
|
|
r->add_function(r, "startswith", "gpt", bench_starts_with_gpt);
|
|
r->add_function(r, "startswith", "yurii", bench_starts_with_yurii);
|
|
r->execute2(r, times, "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnop");
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
void bench_endswith(long times) {
|
|
rbench_t *r = rbench_new();
|
|
r->stdout = false;
|
|
r->show_progress = show_progress;
|
|
rprint("\\T B\\l Times: %ld\n", times);
|
|
r->add_function(r, "endswith", "retoor", bench_ends_with_r);
|
|
r->add_function(r, "endswith", "gpt", bench_ends_with_gpt);
|
|
r->add_function(r, "endswith", "yurii", bench_ends_with_yurii);
|
|
r->execute2(r, times, "abcdefghijklmnopqrstuvwxyzdef", "qrstuvwxyzdef");
|
|
total_execution_time += r->execution_time;
|
|
total_times += times * 2;
|
|
rbench_free(r);
|
|
}
|
|
|
|
#define ifwhile(cond, action) \
|
|
{ \
|
|
bool _did_doit = false; \
|
|
while (cond) { \
|
|
_did_doit = true; \
|
|
{ action } \
|
|
} \
|
|
if (_did_doit)
|
|
|
|
#define endifwhile }
|
|
|
|
int main() {
|
|
show_progress = true;
|
|
long times = 900000000;
|
|
printf("With %% progress times:\n");
|
|
BENCH(times, { bench_starts_with_yurii("abcdefghijklmnopqrstuvw", "abcdef"); });
|
|
BENCH(times, { bench_ends_with_yurii("abcdefghijklmnopqrstuvw", "uvw"); });
|
|
printf("Without %% progress times:\n");
|
|
BENCH(times * 1000, { bench_starts_with_yurii("abcdefghijklmnopqrstuvw", "abcdef"); });
|
|
BENCH(times * 1000, { bench_ends_with_yurii("abcdefghijklmnopqrstuvw", "uvw"); });
|
|
bench_table(times / 10000);
|
|
bench_sprintf(times / 10000);
|
|
bench_format_number(times / 100, 123456789);
|
|
bench_rstrmove(times / 100);
|
|
bench_math(times);
|
|
bench_strcmp(times / 100);
|
|
bench_startswith(times / 10);
|
|
bench_endswith(times / 10);
|
|
printf("\nTotal execution time:%s\n", format_time(total_execution_time));
|
|
printf("Total times: %s\n", rformat_number(total_times));
|
|
return 0;
|
|
} |