Line data Source code
1 : /*
2 : START OF LICENSE STUB
3 : DeDOS: Declarative Dispersion-Oriented Software
4 : Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 :
6 : This program is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : END OF LICENSE STUB
19 : */
20 : /**
21 : * @file stats.c
22 : *
23 : * Functions for the sending and receiving of statsitics between ctrl and runtime
24 : */
25 : #include "stats.h"
26 : #include "logging.h"
27 :
28 : #include <stdlib.h>
29 :
30 : /**
31 : * Header for a serialized stats message.
32 : *
33 : * Comes before a set of samples (i.e. the whole stats message)
34 : */
35 : struct stat_msg_hdr {
36 : /** The number of *items* sampled (not the size of the sample) */
37 : int n_samples;
38 : };
39 :
40 0 : int is_thread_stat(enum stat_id id) {
41 0 : for (int i=0; i < N_REPORTED_THREAD_STAT_TYPES; i++) {
42 0 : if (reported_thread_stat_types[i].id == id) {
43 0 : return 1;
44 : }
45 : }
46 0 : return 0;
47 : }
48 :
49 0 : int is_msu_stat(enum stat_id id) {
50 0 : for (int i=0; i < N_REPORTED_MSU_STAT_TYPES; i++) {
51 0 : if (reported_msu_stat_types[i].id == id) {
52 0 : return 1;
53 : }
54 : }
55 0 : return 0;
56 : }
57 :
58 :
59 :
60 : /** Initializes a single stat sample with room to hold `max_stats` statistics */
61 96 : static int init_stat_sample(int max_stats, struct stat_sample *sample) {
62 96 : sample->max_stats = max_stats;
63 96 : sample->stats = calloc(max_stats, sizeof(*sample->stats));
64 96 : if (sample->stats == NULL) {
65 0 : log_error("Error allocating sample stats");
66 0 : return -1;
67 : }
68 96 : return 0;
69 : }
70 :
71 0 : void free_stat_samples(struct stat_sample *sample, int n_samples) {
72 0 : if (sample != NULL) {
73 0 : for (int i=0; i<n_samples; i++) {
74 0 : free(sample[i].stats);
75 : }
76 0 : free(sample);
77 : }
78 0 : }
79 :
80 0 : struct stat_sample *init_stat_samples(int max_stats, int n_samples) {
81 0 : struct stat_sample *sample = calloc(n_samples, sizeof(*sample));
82 0 : if (sample == NULL) {
83 0 : log_error("Could not allocate %d stat samples", n_samples);
84 0 : return NULL;
85 : }
86 0 : for (int i=0; i<n_samples; i++) {
87 0 : if (init_stat_sample(max_stats, &sample[i]) != 0) {
88 0 : log_error("Error initializing stat sample %d", i);
89 0 : free(sample);
90 0 : return NULL;
91 : }
92 : }
93 0 : return sample;
94 : }
95 :
96 2 : size_t serialized_stat_sample_size(struct stat_sample *sample, int n_samples) {
97 2 : size_t size = sizeof(sample->hdr) * n_samples;
98 98 : for (int i=0; i<n_samples; i++) {
99 96 : size += sizeof(*sample->stats) * sample[i].hdr.n_stats;
100 : }
101 2 : size += sizeof(struct stat_msg_hdr);
102 2 : return size;
103 : }
104 :
105 : /** Serializes a single stat sample into a buffer of size `buff_len`.
106 : * @return 0 on success, -1 if buffer is not large enough to hold sample */
107 48 : static ssize_t serialize_stat_sample(struct stat_sample *sample, void *buffer, size_t buff_len) {
108 48 : if (buff_len < sizeof(sample->hdr) + sizeof(*sample->stats) * sample->hdr.n_stats) {
109 0 : log_error("Buffer isn't large enough to fit serialized stat sample");
110 0 : return -1;
111 : }
112 :
113 48 : char *curr_buff = buffer;
114 48 : memcpy(curr_buff, &sample->hdr, sizeof(sample->hdr));
115 48 : curr_buff += sizeof(sample->hdr);
116 48 : size_t stat_size = sizeof(*sample->stats) * sample->hdr.n_stats;
117 48 : memcpy(curr_buff, sample->stats, stat_size);
118 :
119 48 : return stat_size + sizeof(sample->hdr);
120 : }
121 :
122 1 : ssize_t serialize_stat_samples(struct stat_sample *samples, int n_samples,
123 : void *buffer, size_t buff_len) {
124 1 : if (buff_len < serialized_stat_sample_size(samples, n_samples)) {
125 0 : log_error("Buffer isn't large enough to fit serialized stat samples");
126 0 : return -1;
127 : }
128 :
129 1 : struct stat_msg_hdr hdr = { .n_samples = n_samples };
130 1 : memcpy(buffer, &hdr, sizeof(hdr));
131 1 : hdr.n_samples= n_samples;
132 :
133 1 : char *curr_buff = ((char*)buffer) + sizeof(hdr);
134 1 : char *end_buff = curr_buff + buff_len;
135 :
136 49 : for (int i=0; i<n_samples; i++) {
137 48 : size_t new_size = serialize_stat_sample(&samples[i], curr_buff, end_buff-curr_buff);
138 : if (new_size < 0) {
139 : log_error("Erorr serializing stat sample %d", i);
140 : return -1;
141 : }
142 48 : curr_buff += new_size;
143 : }
144 :
145 1 : log(LOG_STAT_SERIALIZATION, "Serialized %d samples into buffer of size %d",
146 : n_samples, (int)(curr_buff - (char*)buffer));
147 1 : return curr_buff - (char*)buffer;
148 : }
149 :
150 : /** Deserializes a single stat sample from a buffer
151 : * @returns 0 on success, -1 on error
152 : */
153 48 : static ssize_t deserialize_stat_sample(void *buffer, size_t buff_len, struct stat_sample *sample) {
154 48 : if (buff_len < sizeof(sample->hdr)) {
155 0 : log_error("Buffer isn't large enough to fit header");
156 0 : return -1;
157 : }
158 :
159 48 : char *curr_buff = buffer;
160 48 : memcpy(&sample->hdr, buffer, sizeof(sample->hdr));
161 48 : curr_buff += sizeof(sample->hdr);
162 :
163 48 : size_t stat_size = sizeof(*sample->stats) * sample->hdr.n_stats;
164 48 : if (sizeof(sample->hdr) + stat_size > buff_len) {
165 0 : log_error("Buffer isn't large enough to fit statistics");
166 0 : return -1;
167 : }
168 48 : if (sample->max_stats < sample->hdr.n_stats) {
169 0 : log_error("Not enough statistics allocated to fit deserialized stats");
170 0 : return -1;
171 : }
172 48 : memcpy(sample->stats, curr_buff, stat_size);
173 48 : return sizeof(sample->hdr) + stat_size;
174 : }
175 :
176 1 : int deserialize_stat_samples(void *buffer, size_t buff_len, struct stat_sample *samples,
177 : int n_samples) {
178 1 : struct stat_msg_hdr *hdr = buffer;
179 1 : if (buff_len < sizeof(*hdr)) {
180 0 : log_error("Buffer not large enough for stat message header");
181 0 : return -1;
182 : }
183 1 : if (n_samples < hdr->n_samples) {
184 0 : log_error("Number of allocated samples smaller than in serialized buffer");
185 0 : return -1;
186 : }
187 :
188 1 : char *curr_buff = ((char *)buffer) + sizeof(*hdr);
189 1 : char *end_buff = curr_buff + buff_len;
190 49 : for (int i=0; i < hdr->n_samples; i++) {
191 48 : ssize_t consumed = deserialize_stat_sample(curr_buff, end_buff - curr_buff, &samples[i]);
192 48 : if (consumed < 0) {
193 0 : log_error("Error deserializing stat sample %d", i);
194 0 : return -1;
195 : }
196 48 : curr_buff += consumed;
197 : }
198 :
199 1 : log(LOG_STAT_SERIALIZATION, "Deserialized buffer of size %d into %d samples",
200 : ((int)(curr_buff - (char*) buffer)), hdr->n_samples);
201 :
202 1 : if (curr_buff - (char*)buffer < buff_len) {
203 0 : log_warn("Entire buffer not used when deserializing stats");
204 : }
205 1 : return hdr->n_samples;
206 : }
|