/** * @file * @author Caleb Fangmeier * @version 0.1 * * @section LICENSE * * * MIT License * * Copyright (c) 2017 Caleb Fangmeier * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef dataset_hpp #define dataset_hpp #include #include #include #include #include #include #include "value.hpp" #include "container.hpp" #include "memtrack.hpp" #include "config.hpp" #include "log.hpp" #include "TFile.h" namespace fv { void request_stop_callback(int); // Forward Declaration class DataSet; // Forward Declaration DataSet* the_dataset; /* * A DataSet is a generic source of data that is used to populate * ObservedValues. For each ObservedValue, it is recommended that the DataSet * have a field whose value is updated when the load_next() method is called. A * pointer to this value is then passed during the creation of the * ObservedValue. It is important, therefore, that the location in memory of * the data not change from event to event. */ class DataSet { private: void summary() { INFO(GenValue::summary()); } timeval start_time; bool stop_requested; void print_status() { size_t m_used = fv_util::getCurrentRSS() / 1024 / 1024; timeval curr_time; gettimeofday(&curr_time, nullptr); float delta_secs = (curr_time.tv_sec - start_time.tv_sec) + (curr_time.tv_usec - start_time.tv_usec) / 1E6f; int current_event = get_current_event(); float events_per_second = current_event / delta_secs; int secs_remaining = int((get_events() - current_event) / events_per_second); std::stringstream time_remaining; if (secs_remaining > 3600.) { int hours = secs_remaining / 3600; secs_remaining %= 3600; time_remaining << hours << "H "; } if (secs_remaining > 60) { int minutes = secs_remaining / 60; secs_remaining %= 60; time_remaining << minutes << "M "; } if (secs_remaining > 0) { time_remaining << secs_remaining << "S"; } std::cout << "\rprocessing event: " << current_event + 1 << "/" << get_events() << " of file: " << get_current_file().filename << ", " << m_used << "MB used " << ", " << time_remaining.str() << " est. time remaining" << std::flush; } protected: std::map containers; long max_events; virtual int get_events() = 0; virtual int get_current_event() = 0; virtual fv_util::DataFileDescriptor &get_current_file() = 0; std::map get_container_name_value_map() { std::map value_map; for (auto container : containers) value_map[container.first] = container.second->get_value_name(); return value_map; } virtual bool load_next() = 0; virtual void save_config() = 0; public: DataSet() : stop_requested(false){ max_events = fv_util::the_config->get_max_events(); the_dataset = this; signal(SIGINT, request_stop_callback); signal(SIGTERM, request_stop_callback); } bool next(bool verbose=true) { if (stop_requested) return false; int current_event = get_current_event(); if (current_event == 0) gettimeofday(&start_time, nullptr); if (verbose and (((current_event + 1) % 500) == 0 or current_event+1 == get_events())) print_status(); GenValue::reset(); return load_next(); } void set_max_events(const int &max_events) { this->max_events = max_events; } int get_max_events() { return this->max_events; } void request_stop() { stop_requested = true; } virtual void save_all() { for (auto container : containers) container.second->save(); save_config(); } template C *register_container(ArgTypes... args) { C *container = new C(args...); if (containers[container->get_name()] != nullptr) { CRITICAL("Container with name \"" + container->get_name() + "\" already exists."); } containers[container->get_name()] = container; return container; } GenContainer *get_container(std::string container_name) { GenContainer *c = containers[container_name]; if (c == nullptr) { CRITICAL("Request for container \"" << container_name << "\" failed. Doesn't exist."); } return c; } }; void request_stop_callback(int) { std::cout << std::endl << "SIGINT/SIGTERM caught, stopping after current event" << std::endl; the_dataset->request_stop(); } } #endif // dataset_hpp