/** * Copyright 2018 VMware * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _HOTSTUFF_UTIL_H #define _HOTSTUFF_UTIL_H #include "hotstuff/config.h" #include "salticidae/util.h" namespace hotstuff { class Logger: public salticidae::Logger { public: using salticidae::Logger::Logger; void proto(const char *fmt, ...) { va_list ap; va_start(ap, fmt); write("proto", is_tty() ? salticidae::TTY_COLOR_MAGENTA : nullptr, fmt, ap); va_end(ap); } }; extern Logger logger; #ifdef HOTSTUFF_PROTO_LOG #define HOTSTUFF_ENABLE_LOG_PROTO #endif #ifdef HOTSTUFF_DEBUG_LOG #define HOTSTUFF_NORMAL_LOG #define HOTSTUFF_ENABLE_LOG_DEBUG #define HOTSTUFF_ENABLE_LOG_PROTO #endif #ifdef HOTSTUFF_NORMAL_LOG #define HOTSTUFF_ENABLE_LOG_INFO #define HOTSTUFF_ENABLE_LOG_WARN #endif #ifdef HOTSTUFF_ENABLE_LOG_INFO #define HOTSTUFF_LOG_INFO(...) hotstuff::logger.info(__VA_ARGS__) #else #define HOTSTUFF_LOG_INFO(...) ((void)0) #endif #ifdef HOTSTUFF_ENABLE_LOG_DEBUG #define HOTSTUFF_LOG_DEBUG(...) hotstuff::logger.debug(__VA_ARGS__) #else #define HOTSTUFF_LOG_DEBUG(...) ((void)0) #endif #ifdef HOTSTUFF_ENABLE_LOG_WARN #define HOTSTUFF_LOG_WARN(...) hotstuff::logger.warning(__VA_ARGS__) #else #define HOTSTUFF_LOG_WARN(...) ((void)0) #endif #ifdef HOTSTUFF_ENABLE_LOG_PROTO #define HOTSTUFF_LOG_PROTO(...) hotstuff::logger.proto(__VA_ARGS__) #else #define HOTSTUFF_LOG_PROTO(...) ((void)0) #endif #define HOTSTUFF_LOG_ERROR(...) hotstuff::logger.error(__VA_ARGS__) #ifdef HOTSTUFF_BLK_PROFILE class BlockProfiler { enum BlockState { BLK_SEEN, BLK_FETCH, BLK_CC }; struct BlockProfile { bool is_local; /* is the block proposed by the replica itself? */ BlockState state; double hash_seen_time; /* the first time to see block hash */ double full_fetch_time; /* the first time to get full block content */ double cc_time; /* the time when it receives cc */ double commit_time; /* the time when it commits */ }; std::unordered_map blocks; ElapsedTime timer; public: BlockProfiler() { timer.start(); } auto rec_blk(const uint256 &blk_hash, bool is_local) { auto it = blocks.find(blk_hash); assert(it == blocks.end()); timer.stop(false); return blocks.insert(std::make_pair(blk_hash, BlockProfile{is_local, BLK_SEEN, timer.elapsed_sec, 0, 0, 0})).first; } void get_blk(const uint256 &blk_hash) { auto it = blocks.find(blk_hash); if (it == blocks.end()) it = rec_blk(blk_hash, false); BlockProfile &blkp = it->second; assert(blkp.state == BLK_SEEN); timer.stop(false); blkp.full_fetch_time = timer.elapsed_sec; blkp.state = BLK_FETCH; } void have_cc(const uint256 &blk_hash) { auto it = blocks.find(blk_hash); assert(it != blocks.end()); BlockProfile &blkp = it->second; assert(blkp.state == BLK_FETCH); timer.stop(false); blkp.polling_start_time = timer.elapsed_sec; blkp.state = BLK_CC; } const char *decide_blk(const uint256 &blk_hash) { static char buff[1024]; auto it = blocks.find(blk_hash); assert(it != blocks.end()); BlockProfile &blkp = it->second; assert(blkp.state == BLK_CC); timer.stop(false); blkp.commit_time = timer.elapsed_sec; snprintf(buff, sizeof buff, "(%d,%.4f,%.4f,%.4f,%.4f,%.4f)", blkp.is_local, blkp.hash_seen_time, blkp.full_fetch_time, blkp.polling_start_time, blkp.polling_end_time, blkp.commit_time); blocks.erase(it); return buff; } }; #endif } #endif