Commit 03d9cc61 authored by Steffen Vogel's avatar Steffen Vogel 🎅🏼
Browse files

utils: partial port to C++

parent 343ed572
/** Human readable cpusets.
*
* @file
* @author Steffen Vogel <github@daniel-krebs.net>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLAScommon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#ifdef __linux__
#include <sched.h>
#include <cstdint>
#include <villas/exceptions.hpp>
namespace villas {
namespace utils {
class CpuSet {
protected:
cpu_set_t *setp;
unsigned num_cpus;
size_t sz;
public:
CpuSet() :
num_cpus(sizeof(uintmax_t) * 8),
sz(CPU_ALLOC_SIZE(num_cpus))
{
setp = CPU_ALLOC(num_cpus);
if (!setp)
throw new villas::RuntimeError("Failed to allocated memory");
zero();
}
/** Parses string with list of CPU ranges.
*
* @param str Human readable representation of the set.
*/
CpuSet(const std::string &str);
/** Convert integer to cpu_set_t.
*
* @param set An integer number which is used as the mask
*/
CpuSet(uintmax_t set);
/** Convert cpu_set_t to an integer. */
operator uintmax_t();
operator const cpu_set_t*()
{
return setp;
}
/** Returns human readable representation of the cpuset.
*
* The output format is a list of CPUs with ranges (for example, "0,1,3-9").
*/
operator std::string();
~CpuSet()
{
CPU_FREE(setp);
}
CpuSet(const CpuSet &src) :
CpuSet(src.num_cpus)
{
memcpy(setp, src.setp, sz);
}
bool empty() const
{
return count() == 0;
}
bool full() const
{
return count() == num_cpus;
}
unsigned count() const
{
return CPU_COUNT_S(sz, setp);
}
void zero()
{
CPU_ZERO_S(sz, setp);
}
size_t size() const
{
return sz;
}
CpuSet operator~()
{
CpuSet full = UINTMAX_MAX;
return full ^ *this;
}
bool operator==(const CpuSet &rhs)
{
return CPU_EQUAL_S(sz, setp, rhs.setp);
}
CpuSet& operator&=(const CpuSet &rhs)
{
CPU_AND_S(sz, setp, setp, rhs.setp);
return *this;
}
CpuSet& operator|=(const CpuSet &rhs)
{
CPU_OR_S(sz, setp, setp, rhs.setp);
return *this;
}
CpuSet& operator^=(const CpuSet &rhs)
{
CPU_XOR_S(sz, setp, setp, rhs.setp);
return *this;
}
friend CpuSet operator&(CpuSet lhs, const CpuSet &rhs)
{
lhs &= rhs;
return lhs;
}
friend CpuSet operator|(CpuSet lhs, const CpuSet &rhs)
{
lhs |= rhs;
return lhs;
}
friend CpuSet operator^(CpuSet lhs, const CpuSet &rhs)
{
lhs ^= rhs;
return lhs;
}
//bool& operator[](std::size_t cpu)
//{
// void cpuset_set_cpu(cpuset_t*setp, cpu_t cpu, int state)
//}
bool operator[](size_t cpu) const
{
return isset(cpu);
}
bool isset(size_t cpu) const
{
return CPU_ISSET_S(cpu, sz, setp);
}
void clear(size_t cpu)
{
CPU_CLR_S(cpu, sz, setp);
}
void set(size_t cpu)
{
CPU_SET_S(cpu, sz, setp);
}
};
#endif
} // namespace villas
} // namespace utils
#include <fmt/format.h>
......@@ -27,7 +27,6 @@
#include <stdint.h>
#include <sched.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <villas/config.h>
......@@ -37,6 +36,8 @@
extern "C" {
#endif
extern pthread_t main_thread;
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect((x),1)
#define UNLIKELY(x) __builtin_expect((x),0)
......@@ -137,15 +138,6 @@ extern "C" {
#define BITMASK(h, l) (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONGLONG - 1 - (h))))
#define BIT(nr) (1UL << (nr))
/* Forward declarations */
struct timespec;
/** Print copyright message to stdout. */
void print_copyright();
/** Print version to stdout. */
void print_version();
/** Normal random variate generator using the Box-Muller method
*
* @param m Mean
......@@ -178,38 +170,6 @@ char * vstrcatf(char **dest, const char *fmt, va_list va)
#define strf(fmt, ...) strcatf(&(char *) { NULL }, fmt, ##__VA_ARGS__)
#define vstrf(fmt, va) vstrcatf(&(char *) { NULL }, fmt, va)
#ifdef __linux__
/** Convert integer to cpu_set_t.
*
* @param set An integer number which is used as the mask
* @param cset A pointer to the cpu_set_t datastructure
*/
void cpuset_from_integer(uintmax_t set, cpu_set_t *cset);
/** Convert cpu_set_t to an integer. */
void cpuset_to_integer(cpu_set_t *cset, uintmax_t *set);
/** Parses string with list of CPU ranges.
*
* From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c
*
* @retval 0 On success.
* @retval 1 On error.
* @retval 2 If fail is set and a cpu number passed in the list doesn't fit
* into the cpu_set. If fail is not set cpu numbers that do not fit are
* ignored and 0 is returned instead.
*/
int cpulist_parse(const char *str, cpu_set_t *set, int fail);
/** Returns human readable representation of the cpuset.
*
* From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c
*
* The output format is a list of CPUs with ranges (for example, "0,1,3-9").
*/
char * cpulist_create(char *str, size_t len, cpu_set_t *set);
#endif
/** Allocate and initialize memory. */
void * alloc(size_t bytes);
......@@ -219,18 +179,6 @@ void * memdup(const void *src, size_t bytes);
/** Call quit() in the main thread. */
void die();
/** Used by version_parse(), version_compare() */
struct version {
int major;
int minor;
};
/** Compare two versions. */
int version_cmp(struct version *a, struct version *b);
/** Parse a dotted version string. */
int version_parse(const char *s, struct version *v);
/** Check assertion and exit if failed. */
#ifndef assert
#define assert(exp) do { \
......@@ -240,9 +188,6 @@ int version_parse(const char *s, struct version *v);
} while (0)
#endif
/** Fill buffer with random data */
ssize_t read_random(char *buf, size_t len);
/** Get log2 of long long integers */
static inline int log2i(long long x) {
if (x == 0)
......@@ -251,9 +196,6 @@ static inline int log2i(long long x) {
return sizeof(x) * 8 - __builtin_clzll(x) - 1;
}
/** Register a exit callback for program termination: SIGINT, SIGKILL & SIGALRM. */
int signals_init(void (*cb)(int signal, siginfo_t *sinfo, void *ctx));
/** Send signal \p sig to main thread. */
void killme(int sig);
......@@ -262,10 +204,6 @@ pid_t spawn(const char *name, char *const argv[]);
/** Determines the string length as printed on the screen (ignores escable sequences). */
size_t strlenp(const char *str);
/** Remove ANSI control sequences for colored output. */
char * decolor(char *str);
#ifdef __cplusplus
}
#endif
/** Utilities.
*
* @file
* @author Steffen Vogel <github@daniel-krebs.net>
* @author Daniel Krebs <github@daniel-krebs.net>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
......@@ -26,6 +27,8 @@
#include <string>
#include <vector>
#include <signal.h>
namespace villas {
namespace utils {
......@@ -41,6 +44,21 @@ assertExcept(bool condition, const T& exception)
throw exception;
}
/** Print copyright message to stdout. */
void print_copyright();
/** Print version to stdout. */
void print_version();
/** Register a exit callback for program termination: SIGINT, SIGKILL & SIGALRM. */
int signals_init(void (*cb)(int signal, siginfo_t *sinfo, void *ctx));
/** Fill buffer with random data */
ssize_t read_random(char *buf, size_t len);
/** Remove ANSI control sequences for colored output. */
char * decolor(char *str);
} // namespace utils
} // namespace villas
/** Version.
*
* @file
* @author Steffen Vogel <github@daniel-krebs.net>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLAScommon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <string>
namespace villas {
namespace utils {
class Version {
protected:
int components[3];
static int cmp(const Version& lhs, const Version& rhs);
public:
/** Parse a dotted version string. */
Version(const std::string &s);
Version(int maj, int min = 0, int pat = 0);
inline bool operator==(const Version& rhs) { return cmp(*this, rhs) == 0; }
inline bool operator!=(const Version& rhs) { return cmp(*this, rhs) != 0; }
inline bool operator< (const Version& rhs) { return cmp(*this, rhs) < 0; }
inline bool operator> (const Version& rhs) { return cmp(*this, rhs) > 0; }
inline bool operator<=(const Version& rhs) { return cmp(*this, rhs) <= 0; }
inline bool operator>=(const Version& rhs) { return cmp(*this, rhs) >= 0; }
};
} // namespace villas
} // namespace utils
......@@ -44,6 +44,8 @@ add_library(villas-common SHARED
tsc.c
utils.c
utils.cpp
cpuset.cpp
version.cpp
)
if(CMAKE_SYSTEM_NAME STREQUAL Linux)
......
/** Human readable cpusets.
*
* @file
* @author Steffen Vogel <github@daniel-krebs.net>
* @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLAScommon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/cpuset.hpp>
#include <villas/utils.hpp>
using namespace villas::utils;
#ifdef __linux__
CpuSet::operator uintmax_t()
{
uintmax_t iset = 0;
for (size_t i = 0; i < num_cpus; i++) {
if (isset(i))
iset |= 1ULL << i;
}
return iset;
}
CpuSet::CpuSet(uintmax_t iset) :
CpuSet()
{
zero();
for (size_t i = 0; i < num_cpus; i++) {
if (iset & (1L << i))
set(i);
}
}
CpuSet::CpuSet(const std::string &str) :
CpuSet()
{
size_t endpos, start, end;
for (auto token : tokenize(str, ",")) {
auto sep = token.find('-');
if (sep == std::string::npos) {
start = std::stoi(token, &endpos);
if (token.begin() + endpos != token.end())
throw new std::invalid_argument("Not a valid CPU set");
if (start < num_cpus)
set(start);
}
else {
start = std::stoi(token, &endpos);
if (token.begin() + endpos != token.begin() + sep)
throw new std::invalid_argument("Not a valid CPU set");
auto token2 = token.substr(endpos + 1);
end = std::stoi(token2, &endpos);
if (token2.begin() + endpos != token2.end())
throw new std::invalid_argument("Not a valid CPU set");
for (size_t i = start; i <= end && i < num_cpus; i++)
set(i);
}
}
}
CpuSet::operator std::string ()
{
std::stringstream ss;
bool first = true;
for (size_t i = 0; i < num_cpus; i++) {
if (isset(i)) {
size_t run = 0;
for (size_t j = i + 1; j < num_cpus; j++) {
if (!isset(j))
break;
run++;
}
if (first)
first = false;
else
ss << ",";
ss << i;
if (run == 1) {
ss << "," << (i + 1);
i++;
}
else if (run > 1) {
ss << "-" << (i + run);
i += run;
}
}
}
return ss.str();
}
#endif /* __linux__ */
......@@ -23,44 +23,20 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <pthread.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <villas/config.h>
#include <villas/utils.h>
pthread_t main_thread;
void print_copyright()
{
printf(PROJECT_NAME " %s (built on %s %s)\n",
CLR_BLU(PROJECT_BUILD_ID), CLR_MAG(__DATE__), CLR_MAG(__TIME__));
printf(" Copyright 2014-2017, Institute for Automation of Complex Power Systems, EONERC\n");
printf(" Steffen Vogel <StVogel@eonerc.rwth-aachen.de>\n");
}
void print_version()
{
printf("%s\n", PROJECT_BUILD_ID);
}
int version_parse(const char *s, struct version *v)
{
return sscanf(s, "%u.%u", &v->major, &v->minor) != 2;
}
int version_cmp(struct version *a, struct version *b) {
int major = a->major - b->major;
int minor = a->minor - b->minor;
return major ? major : minor;
}
double box_muller(float m, float s)
{
double x1, x2, y1;
......@@ -118,128 +94,6 @@ char * vstrcatf(char **dest, const char *fmt, va_list ap)
return *dest;
}
#ifdef __linux__
void cpuset_to_integer(cpu_set_t *cset, uintmax_t *set)
{
*set = 0;
for (int i = 0; i < MIN(sizeof(*set) * 8, CPU_SETSIZE); i++) {
if (CPU_ISSET(i, cset))
*set |= 1ULL << i;
}
}
void cpuset_from_integer(uintmax_t set, cpu_set_t *cset)
{
CPU_ZERO(cset);
for (int i = 0; i < MIN(sizeof(set) * 8, CPU_SETSIZE); i++) {
if (set & (1L << i))
CPU_SET(i, cset);
}
}
/* From: https://github.com/mmalecki/util-linux/blob/master/lib/cpuset.c */
static const char *nexttoken(const char *q, int sep)
{
if (q)
q = strchr(q, sep);
if (q)
q++;
return q;
}
int cpulist_parse(const char *str, cpu_set_t *set, int fail)
{
const char *p, *q;
int r = 0;
q = str;
CPU_ZERO(set);