GNUnet  0.19.4
benchmark.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2018 GNUnet e.V.
4 
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.
9 
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.
14 
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "benchmark.h"
31 #include <pthread.h>
32 #include <sys/syscall.h>
33 
37 static pthread_key_t key;
38 
42 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
43 
44 
50 static void
52 {
53  struct GNUNET_DISK_FileHandle *fh;
54  pid_t pid = getpid ();
55  pid_t tid = syscall (SYS_gettid);
56  char *benchmark_dir;
57  char *s;
58 
59  benchmark_dir = getenv ("GNUNET_BENCHMARK_DIR");
60 
61  if (NULL == benchmark_dir)
62  return;
63 
64  if (GNUNET_OK != GNUNET_DISK_directory_create (benchmark_dir))
65  {
66  GNUNET_break (0);
67  return;
68  }
69 
70  GNUNET_asprintf (&s, "%s/gnunet-benchmark-ops-%s-%llu-%llu.txt",
71  benchmark_dir,
72  (pid == tid) ? "main" : "thread",
73  (unsigned long long) pid,
74  (unsigned long long) tid);
75 
82  GNUNET_assert (NULL != fh);
83  GNUNET_free (s);
84 
85 #define WRITE_BENCHMARK_OP(opname) do { \
86  GNUNET_asprintf (&s, "op " #opname " count %llu time_us %llu\n", \
87  (unsigned long long) bd->opname ## _count, \
88  (unsigned long long) bd->opname ## _time.rel_value_us); \
89  GNUNET_assert (GNUNET_SYSERR != GNUNET_DISK_file_write_blocking (fh, s, \
90  strlen ( \
91  s))); \
92  GNUNET_free (s); \
93 } while (0)
94 
95  WRITE_BENCHMARK_OP (ecc_ecdh);
96  WRITE_BENCHMARK_OP (ecdh_eddsa);
97  WRITE_BENCHMARK_OP (ecdhe_key_create);
98  WRITE_BENCHMARK_OP (ecdhe_key_get_public);
99  WRITE_BENCHMARK_OP (ecdsa_ecdh);
100  WRITE_BENCHMARK_OP (ecdsa_key_create);
101  WRITE_BENCHMARK_OP (ecdsa_key_get_public);
102  WRITE_BENCHMARK_OP (ecdsa_sign);
103  WRITE_BENCHMARK_OP (ecdsa_verify);
104  WRITE_BENCHMARK_OP (eddsa_ecdh);
105  WRITE_BENCHMARK_OP (eddsa_key_create);
106  WRITE_BENCHMARK_OP (eddsa_key_get_public);
107  WRITE_BENCHMARK_OP (eddsa_sign);
108  WRITE_BENCHMARK_OP (eddsa_verify);
109  WRITE_BENCHMARK_OP (hash);
110  WRITE_BENCHMARK_OP (hash_context_finish);
111  WRITE_BENCHMARK_OP (hash_context_read);
112  WRITE_BENCHMARK_OP (hash_context_start);
113  WRITE_BENCHMARK_OP (hkdf);
114  WRITE_BENCHMARK_OP (rsa_blind);
115  WRITE_BENCHMARK_OP (rsa_private_key_create);
116  WRITE_BENCHMARK_OP (rsa_private_key_get_public);
117  WRITE_BENCHMARK_OP (rsa_sign_blinded);
118  WRITE_BENCHMARK_OP (rsa_unblind);
119  WRITE_BENCHMARK_OP (rsa_verify);
120 
121 #undef WRITE_BENCHMARK_OP
122 
124 
125  GNUNET_asprintf (&s, "%s/gnunet-benchmark-urls-%s-%llu-%llu.txt",
126  benchmark_dir,
127  (pid == tid) ? "main" : "thread",
128  (unsigned long long) pid,
129  (unsigned long long) tid);
130 
137  GNUNET_assert (NULL != fh);
138  GNUNET_free (s);
139 
140  for (unsigned int i = 0; i < bd->urd_len; i++)
141  {
142  struct UrlRequestData *urd = &bd->urd[i];
143  GNUNET_asprintf (&s,
144  "url %s status %u count %llu time_us %llu time_us_max %llu bytes_sent %llu bytes_received %llu\n",
145  urd->request_url,
146  urd->status,
147  (unsigned long long) urd->count,
148  (unsigned long long) urd->time.rel_value_us,
149  (unsigned long long) urd->time_max.rel_value_us,
150  (unsigned long long) urd->bytes_sent,
151  (unsigned long long) urd->bytes_received);
153  strlen (
154  s)));
155  GNUNET_free (s);
156  }
157 
159 }
160 
161 
165 static void
167 {
168  struct BenchmarkData *bd;
169 
170  bd = pthread_getspecific (key);
171  if (NULL != bd)
173 }
174 
175 
181 static void
182 thread_destructor (void *cls)
183 {
184  struct BenchmarkData *bd = cls;
185 
186  // main thread will be handled by atexit
187  if (getpid () == (pid_t) syscall (SYS_gettid))
188  return;
189 
190  GNUNET_assert (NULL != bd);
192 }
193 
194 
198 static void
200 {
201  (void) pthread_key_create (&key, &thread_destructor);
202 }
203 
204 
211 struct BenchmarkData *
213 {
214  struct BenchmarkData *bd;
215 
216  (void) pthread_once (&key_once, &make_key);
217 
218  if (NULL == (bd = pthread_getspecific (key)))
219  {
220  bd = GNUNET_new (struct BenchmarkData);
221  (void) pthread_setspecific (key, bd);
222  if (getpid () == (pid_t) syscall (SYS_gettid))
223  {
224  // We're the main thread!
225  atexit (main_thread_destructor);
226  }
227  }
228  return bd;
229 }
230 
231 
241 struct UrlRequestData *
242 get_url_benchmark_data (char *url, unsigned int status)
243 {
244  char trunc[MAX_BENCHMARK_URL_LEN];
245  struct BenchmarkData *bd;
246 
247  if (NULL == url)
248  {
249  /* Should not happen unless curl barfs */
250  GNUNET_break (0);
251  url = "<empty>";
252  }
253 
254  memcpy (trunc, url, MAX_BENCHMARK_URL_LEN);
255  trunc[MAX_BENCHMARK_URL_LEN - 1] = 0;
256 
257  /* We're not interested in what's after the query string */
258  for (size_t i = 0; i < strlen (trunc); i++)
259  {
260  if (trunc[i] == '?')
261  {
262  trunc[i] = 0;
263  break;
264  }
265  }
266 
267  bd = get_benchmark_data ();
268 
269  GNUNET_assert (bd->urd_len <= bd->urd_capacity);
270 
271  for (unsigned int i = 0; i < bd->urd_len; i++)
272  {
273  if ((0 == strcmp (trunc, bd->urd[i].request_url)) &&
274  (bd->urd[i].status == status))
275  return &bd->urd[i];
276  }
277 
278  {
279  struct UrlRequestData urd = { 0 };
280 
281  memcpy (&urd.request_url, trunc, MAX_BENCHMARK_URL_LEN);
282  urd.status = status;
283 
284  if (bd->urd_len == bd->urd_capacity)
285  {
286  bd->urd_capacity = 2 * (bd->urd_capacity + 1);
287  bd->urd = GNUNET_realloc (bd->urd, bd->urd_capacity * sizeof(struct
288  UrlRequestData));
289  }
290 
291  bd->urd[bd->urd_len++] = urd;
292  return &bd->urd[bd->urd_len - 1];
293  }
294 }
static void make_key()
Initialize the thread-local variable key for benchmark data.
Definition: benchmark.c:199
struct BenchmarkData * get_benchmark_data(void)
Acquire the benchmark data for the current thread, allocate if necessary.
Definition: benchmark.c:212
#define WRITE_BENCHMARK_OP(opname)
struct UrlRequestData * get_url_benchmark_data(char *url, unsigned int status)
Get benchmark data for a URL.
Definition: benchmark.c:242
static void thread_destructor(void *cls)
Called when a thread exits and benchmark data for it was created.
Definition: benchmark.c:182
static pthread_once_t key_once
One-time initialization marker for key.
Definition: benchmark.c:42
static void main_thread_destructor()
Called when the main thread exits and benchmark data for it was created.
Definition: benchmark.c:166
static pthread_key_t key
Thread-local storage key for the benchmark data.
Definition: benchmark.c:37
static void write_benchmark_data(struct BenchmarkData *bd)
Write benchmark data to a file.
Definition: benchmark.c:51
benchmarking for various operations
#define MAX_BENCHMARK_URL_LEN
Maximum length of URLs considered for benchmarking.
Definition: benchmark.h:36
char * getenv()
uint16_t status
See PRISM_STATUS_*-constants.
static struct GNUNET_SCHEDULER_Task * tid
Task identifier of the task that waits for stdin.
static struct GNUNET_DISK_FileHandle * fh
File handle to STDIN, for reading restart/quit commands.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1237
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1308
ssize_t GNUNET_DISK_file_write_blocking(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file, blocking, if necessary.
Definition: disk.c:701
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create(const char *dir)
Implementation of "mkdir -p".
Definition: disk.c:496
@ GNUNET_DISK_OPEN_WRITE
Open the file for writing.
@ GNUNET_DISK_OPEN_TRUNCATE
Truncate file if it exists.
@ GNUNET_DISK_OPEN_CREATE
Create file if it doesn't exist.
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_free(ptr)
Wrapper around free.
Thread-local struct for benchmarking data.
Definition: benchmark.h:116
unsigned int urd_capacity
Definition: benchmark.h:147
struct UrlRequestData * urd
Definition: benchmark.h:143
unsigned int urd_len
Definition: benchmark.h:145
Handle used to access files (and pipes).
uint64_t rel_value_us
The actual value.
Struct for benchmark data for one URL.
Definition: benchmark.h:66
struct GNUNET_TIME_Relative time
Total time spent requesting this URL.
Definition: benchmark.h:95
char request_url[128]
Request URL, truncated (but 0-terminated).
Definition: benchmark.h:70
unsigned int status
HTTP status code.
Definition: benchmark.h:75
uint64_t bytes_received
How many bytes were received in total as response to requesting this URL.
Definition: benchmark.h:90
struct GNUNET_TIME_Relative time_max
Slowest time to response.
Definition: benchmark.h:100
uint64_t bytes_sent
How many bytes were sent in total to request the URL.
Definition: benchmark.h:85
uint64_t count
How often was the URL requested?
Definition: benchmark.h:80