2 This file is part of GNUnet.
3 Copyright (C) 2018 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file util/benchmark.c
21 * @brief benchmarking for various operations
22 * @author Florian Dold <flo@dold.me>
26 #include "gnunet_util_lib.h"
27 #include "benchmark.h"
29 #include <sys/syscall.h>
32 * Thread-local storage key for the benchmark data.
34 static pthread_key_t key;
37 * One-time initialization marker for key.
39 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
43 * Write benchmark data to a file.
45 * @param bd the benchmark data
48 write_benchmark_data (struct BenchmarkData *bd)
50 struct GNUNET_DISK_FileHandle *fh;
51 pid_t pid = getpid ();
52 pid_t tid = syscall (SYS_gettid);
55 GNUNET_asprintf (&s, "gnunet-benchmark-%llu-%llu.txt",
56 (unsigned long long) pid,
57 (unsigned long long) tid);
59 fh = GNUNET_DISK_file_open (s,
60 (GNUNET_DISK_OPEN_WRITE |
61 GNUNET_DISK_OPEN_TRUNCATE |
62 GNUNET_DISK_OPEN_CREATE),
63 (GNUNET_DISK_PERM_USER_READ |
64 GNUNET_DISK_PERM_USER_WRITE));
65 GNUNET_assert (NULL != fh);
68 GNUNET_asprintf (&s, "eddsa_sign_count %llu",
69 (unsigned long long) bd->eddsa_sign_count);
70 GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s, strlen (s)));
73 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
75 GNUNET_asprintf (&s, "gnunet-benchmark-urls-%llu-%llu.txt",
76 (unsigned long long) pid,
77 (unsigned long long) tid);
79 fh = GNUNET_DISK_file_open (s,
80 (GNUNET_DISK_OPEN_WRITE |
81 GNUNET_DISK_OPEN_TRUNCATE |
82 GNUNET_DISK_OPEN_CREATE),
83 (GNUNET_DISK_PERM_USER_READ |
84 GNUNET_DISK_PERM_USER_WRITE));
85 GNUNET_assert (NULL != fh);
88 for (unsigned int i = 0; i < bd->urd_len; i++)
90 struct UrlRequestData *urd = &bd->urd[i];
91 GNUNET_asprintf (&s, "url %s count %lld time_us %lld\n",
93 (unsigned long long) urd->count,
94 (unsigned long long) urd->time.rel_value_us);
95 GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s, strlen (s)));
99 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
104 * Called when the main thread exits and benchmark data for it was created.
107 main_thread_destructor ()
109 struct BenchmarkData *bd;
111 bd = pthread_getspecific (key);
113 write_benchmark_data (bd);
118 * Called when a thread exits and benchmark data for it was created.
123 thread_destructor (void *cls)
125 struct BenchmarkData *bd = cls;
127 // main thread will be handled by atexit
128 if (getpid () == (pid_t) syscall (SYS_gettid))
131 GNUNET_assert (NULL != bd);
136 * Initialize the thread-local variable key for benchmark data.
141 (void) pthread_key_create (&key, &thread_destructor);
146 * Acquire the benchmark data for the current thread, allocate if necessary.
147 * Installs handler to collect the benchmark data on thread termination.
149 * @return benchmark data for the current thread
151 struct BenchmarkData *
152 get_benchmark_data (void)
154 struct BenchmarkData *bd;
156 (void) pthread_once (&key_once, &make_key);
158 if (NULL == (bd = pthread_getspecific (key)))
160 bd = GNUNET_new (struct BenchmarkData);
161 (void) pthread_setspecific (key, bd);
162 if (getpid () == (pid_t) syscall (SYS_gettid))
164 // We're the main thread!
165 atexit (main_thread_destructor);
173 * Get benchmark data for a URL. If the URL is too long, it's truncated
174 * before looking up the correspoding benchmark data.
176 * @param url url to get request data for
178 struct UrlRequestData *
179 get_url_benchmark_data (char *url)
181 char trunc[MAX_BENCHMARK_URL_LEN];
182 struct BenchmarkData *bd;
186 /* Should not happen unless curl barfs */
191 memcpy (trunc, url, MAX_BENCHMARK_URL_LEN);
192 trunc[MAX_BENCHMARK_URL_LEN - 1] = 0;
194 bd = get_benchmark_data ();
196 for (unsigned int i = 0; i < bd->urd_len; i++)
198 if (0 == strcmp (trunc, bd->urd[i].request_url))
203 struct UrlRequestData urd = { 0 };
205 memcpy (&urd.request_url, trunc, MAX_BENCHMARK_URL_LEN);
207 if (bd->urd_len == bd->urd_capacity)
209 bd->urd_capacity = 2 * (bd->urd_capacity + 1);
210 bd->urd = GNUNET_realloc (bd->urd, bd->urd_capacity * sizeof (struct UrlRequestData));
213 bd->urd[bd->urd_len++] = urd;
214 return &bd->urd[bd->urd_len - 1];