logging for master
[oweals/gnunet.git] / src / ats-tests / perf_ats_logging.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010-2013 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  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  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file ats/perf_ats_logging.c
22  * @brief ats benchmark: logging for performance tests
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "perf_ats.h"
29
30 #define LOGGING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
31
32 static GNUNET_SCHEDULER_TaskIdentifier log_task;
33
34 static struct BenchmarkPeer *peers;
35 static int num_peers;
36 static char *name;
37
38 struct LoggingTimestep
39 {
40   struct LoggingTimestep *next;
41   struct LoggingTimestep *prev;
42
43   struct GNUNET_TIME_Absolute timestamp;
44
45   /**
46    * Total number of messages this peer has sent
47    */
48   unsigned int total_messages_sent;
49
50   /**
51    * Total number of bytes this peer has sent
52    */
53   unsigned int total_bytes_sent;
54
55   /**
56    * Total number of messages this peer has received
57    */
58   unsigned int total_messages_received;
59
60   /**
61    * Total number of bytes this peer has received
62    */
63   unsigned int total_bytes_received;
64 };
65
66 struct LoggingPeer
67 {
68   struct BenchmarkPeer *peer;
69
70   struct GNUNET_TIME_Absolute start;
71
72   struct LoggingTimestep *head;
73   struct LoggingTimestep *tail;
74 };
75
76 /**
77  * Log structure of length num_peers
78  */
79 static struct LoggingPeer *lp;
80
81
82 static void
83 write_to_file ()
84 {
85   struct GNUNET_DISK_FileHandle *f;
86   char * filename;
87   char *data;
88   struct LoggingTimestep *cur;
89   int c_m;
90   unsigned int throughput_recv;
91   unsigned int throughput_send;
92   double mult;
93
94   GNUNET_asprintf (&filename, "%llu_%s.data", GNUNET_TIME_absolute_get().abs_value_us,name);
95
96   f = GNUNET_DISK_file_open (filename,
97       GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
98       GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
99   if (NULL == f)
100   {
101     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot open log file `%s'\n", filename);
102     GNUNET_free (filename);
103     return;
104   }
105
106   for (c_m = 0; c_m < num_peers; c_m++)
107   {
108     for (cur = lp[c_m].head; NULL != cur; cur = cur->next)
109     {
110       mult = (1.0 * 1000 * 1000) /  (LOGGING_FREQUENCY.rel_value_us);
111       if (NULL != cur->prev)
112       {
113         throughput_send = cur->total_bytes_sent - cur->prev->total_bytes_sent;
114         throughput_recv = cur->total_bytes_received - cur->prev->total_bytes_received;
115       }
116       else
117       {
118         throughput_send = cur->total_bytes_sent;
119         throughput_recv = cur->total_bytes_received;
120       }
121       throughput_send *= mult;
122       throughput_recv *= mult;
123
124
125       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
126           "Master [%u]: timestamp %llu %llu %u %u %u ; %u %u %u\n", lp[c_m].peer->no,
127           cur->timestamp, GNUNET_TIME_absolute_get_difference(lp[c_m].start,cur->timestamp).rel_value_us / 1000,
128           cur->total_messages_sent, cur->total_bytes_sent, throughput_send,
129           cur->total_messages_received, cur->total_bytes_received, throughput_recv);
130
131       GNUNET_asprintf (&data, "%llu;%llu;%u;%u;%u;%u;%u;%u\n",
132           cur->timestamp,
133           GNUNET_TIME_absolute_get_difference(lp[c_m].start,cur->timestamp).rel_value_us / 1000,
134           cur->total_messages_sent, cur->total_bytes_sent, throughput_send,
135           cur->total_messages_received, cur->total_bytes_received, throughput_recv);
136
137       if (GNUNET_SYSERR == GNUNET_DISK_file_write(f, data, strlen(data)))
138         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot write data to log file `%s'\n", filename);
139       GNUNET_free (data);
140     }
141   }
142
143   if (GNUNET_SYSERR == GNUNET_DISK_file_close(f))
144   {
145     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot close log file `%s'\n", filename);
146     GNUNET_free (filename);
147     return;
148   }
149
150   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Data file successfully written to log file `%s'\n", filename);
151   GNUNET_free (filename);
152 }
153
154 static void
155 collect_log_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
156 {
157   int c_m;
158   int c_s;
159   struct LoggingTimestep *lt;
160   struct BenchmarkPartner *p;
161
162   log_task = GNUNET_SCHEDULER_NO_TASK;
163
164   for (c_m = 0; c_m < num_peers; c_m++)
165   {
166     lt = GNUNET_malloc (sizeof (struct LoggingTimestep));
167     GNUNET_CONTAINER_DLL_insert_tail(lp[c_m].head, lp[c_m].tail, lt);
168
169     /* Collect data */
170     lt->timestamp = GNUNET_TIME_absolute_get();
171     lt->total_bytes_sent = lp[c_m].peer->total_bytes_sent;
172     lt->total_messages_sent = lp[c_m].peer->total_messages_sent;
173     lt->total_bytes_received = lp[c_m].peer->total_bytes_received;
174     lt->total_messages_received = lp[c_m].peer->total_messages_received;
175
176     for (c_s = 0; c_s < lp[c_m].peer->num_partners; c_s++)
177     {
178       p = &peers[c_m].partners[c_s];
179 /*
180       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
181           "Master [%u]: slave [%u]\n",
182           lp->peer->no, p->dest->no);
183 */
184     }
185   }
186
187   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
188     return;
189
190   log_task = GNUNET_SCHEDULER_add_delayed (LOGGING_FREQUENCY,
191       &collect_log_task, NULL);
192 }
193
194
195 void
196 perf_logging_stop ()
197 {
198   int c_m;
199   struct GNUNET_SCHEDULER_TaskContext tc;
200   struct LoggingTimestep *cur;
201
202   if (GNUNET_SCHEDULER_NO_TASK != log_task)
203     GNUNET_SCHEDULER_cancel (log_task);
204   log_task = GNUNET_SCHEDULER_NO_TASK;
205   tc.reason = GNUNET_SCHEDULER_REASON_SHUTDOWN;
206   collect_log_task (NULL, &tc);
207
208   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
209       _("Stop logging\n"));
210
211   write_to_file ();
212
213   for (c_m = 0; c_m < num_peers; c_m++)
214   {
215     while (NULL != (cur = lp[c_m].head))
216     {
217       GNUNET_CONTAINER_DLL_remove (lp[c_m].head, lp[c_m].tail, cur);
218       GNUNET_free (cur);
219     }
220   }
221
222   GNUNET_free (lp);
223 }
224
225 void
226 perf_logging_start (char * testname, struct BenchmarkPeer *masters, int num_masters)
227 {
228   int c_m;
229   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
230       _("Start logging `%s'\n"), testname);
231
232   peers = masters;
233   num_peers = num_masters;
234   name = testname;
235
236   lp = GNUNET_malloc (num_masters * sizeof (struct LoggingPeer));
237
238   for (c_m = 0; c_m < num_masters; c_m ++)
239   {
240     lp[c_m].peer = &masters[c_m];
241     lp[c_m].start = GNUNET_TIME_absolute_get();
242   }
243
244   /* Schedule logging task */
245   log_task = GNUNET_SCHEDULER_add_now (&collect_log_task, NULL);
246 }
247 /* end of file perf_ats_logging.c */
248