LCOV - code coverage report
Current view: top level - common - stats.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 54 100 54.0 %
Date: 2018-01-11 Functions: 6 10 60.0 %

          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             : }

Generated by: LCOV version 1.10