Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
dcdb
dcdb
Commits
f0b8f7bf
Commit
f0b8f7bf
authored
Oct 05, 2018
by
Micha Mueller
Browse files
Adapt perfevent plugin to sensorgroupsV2 architecture
parent
7d45a2a1
Changes
9
Hide whitespace changes
Inline
Side-by-side
config/perfevent.conf
View file @
f0b8f7bf
sensorTemplates
{
sensor
def1
{
interval
5000
mqttsuffix
0222
minValues
5
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_INSTRUCTIONS
}
template_group
def1
{
interval
5000
mqttpart
02
minValues
5
sensor
def2
{
interval
2000
type
PERF_TYPE_HARDWARE
counter
hw_instructions
{
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_INSTRUCTIONS
mqttsuffix
22
}
}
template_group
def2
{
interval
2000
cpus
1
,
2
}
}
sensors
{
sensor
hw_instructions
{
default
def1
mqttsuffix
0020
}
group
hw_i
{
default
def1
mqttpart
23
}
sensor
hw_branch_instructions
{
default
def2
mqttsuffix
0024
group
hw_bi
{
default
def2
mqttpart
0024
counter
hw_branch_instructions
{
mqttsuffix
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_BRANCH_INSTRUCTIONS
}
}
group
hw_bm
{
default
def2
cpus
0
,
2
-
3
mqttpart
002
C
senso
r
hw_branch_misses
{
default
def2
mqttsuffix
002
C
counte
r
hw_branch_misses
{
mqttsuffix
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_BRANCH_MISSES
cpus
0
,
2
-
3
}
}
groups
{
group
cache
{
interval
2000
mqttprefix
02
minValues
3
cpus
2
-
3
sensor
references
{
mqttsuffix
10
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_CACHE_REFERENCES
}
sensor
misses
{
mqttsuffix
20
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_CACHE_MISSES
}
group
cache
{
interval
2000
mqttpart
02
minValues
3
cpus
2
-
3
counter
references
{
mqttsuffix
10
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_CACHE_REFERENCES
}
group
sw
{
interval
1000
mqttprefix
03
minValues
3
cpus
1
-
4
sensor
sw_pagefaults
{
mqttsuffix
30
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_PAGE_FAULTS
}
counter
misses
{
mqttsuffix
20
type
PERF_TYPE_HARDWARE
config
PERF_COUNT_HW_CACHE_MISSES
}
}
sensor
sw_context_switches
{
mqttsuffix
34
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_CONTEXT_SWITCHES
}
group
sw
{
interval
1000
mqttpart
03
minValues
3
cpus
1
-
4
counter
sw_pagefaults
{
mqttsuffix
30
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_PAGE_FAULTS
}
counter
sw_context_switches
{
mqttsuffix
34
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_CONTEXT_SWITCHES
}
sensor
sw_cpu_migrations
{
mqttsuffix
38
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_CPU_MIGRATIONS
}
counter
sw_cpu_migrations
{
mqttsuffix
38
type
PERF_TYPE_SOFTWARE
config
PERF_COUNT_SW_CPU_MIGRATIONS
}
}
src/includes/ConfiguratorTemplate.h
View file @
f0b8f7bf
...
...
@@ -73,11 +73,13 @@ public:
/**
* Read in the given configuration
*
* Overwriting this method is only required if a custom logic is really necessary!
*
* @param cfgPath Path to the config-file
*
* @return True on success, false otherwise
*/
bool
readConfig
(
std
::
string
cfgPath
)
final
{
bool
readConfig
(
std
::
string
cfgPath
)
{
_cfgPath
=
cfgPath
;
boost
::
property_tree
::
iptree
cfg
;
...
...
@@ -214,7 +216,7 @@ public:
return
_sensorGroupInterfaces
;
}
pr
ivate
:
pr
otected
:
void
storeSensorGroup
(
SGroup
*
sGroup
)
{
_sensorGroups
.
push_back
(
sGroup
);
_sensorGroupInterfaces
.
push_back
(
sGroup
);
...
...
@@ -380,7 +382,6 @@ private:
return
true
;
}
protected:
/**
* Virtual interface method, responsible for setting global values specifically
* for its plugin.
...
...
src/sensors/perfevent/PerfAttributes.h
deleted
100644 → 0
View file @
7d45a2a1
/*
* PerfAttributes.h
*
* Created on: 13.08.2018
* Author: Micha Mueller
*/
#ifndef PERFEVENT_PERFATTRIBUTES_H_
#define PERFEVENT_PERFATTRIBUTES_H_
class
PerfAttributes
{
public:
PerfAttributes
()
:
_cpuId
(
0
),
_fd
(
-
1
)
{}
virtual
~
PerfAttributes
()
{}
int
getCpuId
()
const
{
return
_cpuId
;
}
void
setCpuId
(
int
cpuId
)
{
_cpuId
=
cpuId
;
}
protected:
int
_cpuId
;
int
_fd
;
};
#endif
/* PERFEVENT_PERFATTRIBUTES_H_ */
src/sensors/perfevent/PerfSensorGroup.cpp
View file @
f0b8f7bf
...
...
@@ -25,11 +25,12 @@ struct read_format {
}
values
[];
};
PerfSensorGroup
::
PerfSensorGroup
(
const
std
::
string
name
)
:
SensorGroupTemplate
(
name
)
{
_bufSize
=
0
;
_buf
=
NULL
;
PerfSensorGroup
::
PerfSensorGroup
(
const
std
::
string
&
name
)
:
SensorGroupTemplate
(
name
),
_cpuId
(
0
),
_fd
(
-
1
),
_bufSize
(
0
)
{
_buf
=
nullptr
;
}
PerfSensorGroup
::~
PerfSensorGroup
()
{
...
...
@@ -39,8 +40,7 @@ PerfSensorGroup::~PerfSensorGroup() {
}
void
PerfSensorGroup
::
init
(
boost
::
asio
::
io_service
&
io
)
{
_cacheSize
=
_cacheInterval
/
_interval
+
1
;
_timer
.
reset
(
new
boost
::
asio
::
deadline_timer
(
io
,
boost
::
posix_time
::
seconds
(
0
)));
SensorGroupTemplate
::
init
(
io
);
std
::
size_t
bufSize
=
_sensors
.
size
()
*
16
+
8
;
if
(
!
_buf
)
{
...
...
@@ -51,10 +51,6 @@ void PerfSensorGroup::init(boost::asio::io_service& io) {
_buf
=
new
char
[
bufSize
];
_bufSize
=
bufSize
;
}
for
(
auto
s
:
_sensors
)
{
s
->
initSensor
(
_cacheSize
);
}
}
void
PerfSensorGroup
::
start
()
{
...
...
src/sensors/perfevent/PerfSensorGroup.h
View file @
f0b8f7bf
...
...
@@ -9,22 +9,27 @@
#define PERFSENSORGROUP_H_
#include
"../../includes/SensorGroupTemplate.h"
#include
"PerfAttributes.h"
#include
"PerfSensorBase.h"
class
PerfSensorGroup
:
public
SensorGroupTemplate
<
PerfSensorBase
>
,
public
PerfAttributes
{
class
PerfSensorGroup
:
public
SensorGroupTemplate
<
PerfSensorBase
>
{
public:
PerfSensorGroup
(
const
std
::
string
name
);
PerfSensorGroup
(
const
std
::
string
&
name
);
virtual
~
PerfSensorGroup
();
void
init
(
boost
::
asio
::
io_service
&
io
)
override
;
void
start
()
override
;
void
stop
()
override
;
int
getCpuId
()
const
{
return
_cpuId
;
}
void
setCpuId
(
int
cpuId
)
{
_cpuId
=
cpuId
;
}
private:
void
read
()
override
;
void
readAsync
()
override
;
int
_cpuId
;
int
_fd
;
char
*
_buf
;
std
::
size_t
_bufSize
;
std
::
vector
<
uint64_t
>
_ids
;
...
...
src/sensors/perfevent/PerfSingleSensor.cpp
deleted
100644 → 0
View file @
7d45a2a1
/*
* PerfSingleSensor.cpp
*
* Created on: 11.12.2017
* Author: Micha Mueller
*/
#include
"PerfSingleSensor.h"
#include
"timestamp.h"
#include
<unistd.h>
#include
<sys/ioctl.h>
#include
<linux/perf_event.h>
#include
<linux/hw_breakpoint.h>
#include
<asm/unistd.h>
#include
<functional>
#include
<limits.h>
PerfSingleSensor
::
PerfSingleSensor
(
const
std
::
string
&
name
)
:
SensorBase
(
name
),
PerfSensorBase
(
name
),
SingleSensor
(
name
)
{}
PerfSingleSensor
::~
PerfSingleSensor
()
{}
void
PerfSingleSensor
::
start
()
{
if
(
_keepRunning
)
{
//we have been started already
LOG
(
info
)
<<
"Sensor "
<<
_name
<<
" already running."
;
return
;
}
//open perf-counter
struct
perf_event_attr
pe
;
memset
(
&
pe
,
0
,
sizeof
(
struct
perf_event_attr
));
pe
.
type
=
_type
;
pe
.
size
=
sizeof
(
struct
perf_event_attr
);
pe
.
config
=
_config
;
pe
.
disabled
=
1
;
pe
.
exclude_kernel
=
0
;
pe
.
exclude_hv
=
1
;
//perf_event_open()
_fd
=
syscall
(
__NR_perf_event_open
,
&
pe
,
-
1
,
_cpuId
,
-
1
,
0
);
if
(
_fd
==
-
1
)
{
LOG
(
error
)
<<
"Failed to open performance-counter
\"
"
<<
_name
<<
"
\"
"
;
return
;
}
ioctl
(
_fd
,
PERF_EVENT_IOC_RESET
,
0
);
ioctl
(
_fd
,
PERF_EVENT_IOC_ENABLE
,
0
);
_keepRunning
=
1
;
_pendingTasks
++
;
_timer
->
async_wait
(
std
::
bind
(
&
PerfSingleSensor
::
readAsync
,
this
));
LOG
(
info
)
<<
"Sensor "
<<
_name
<<
" started."
;
}
void
PerfSingleSensor
::
stop
()
{
_keepRunning
=
0
;
if
(
_fd
!=
-
1
)
{
close
(
_fd
);
_fd
=
-
1
;
}
LOG
(
info
)
<<
"Sensor "
<<
_name
<<
" stopped."
;
}
void
PerfSingleSensor
::
storeReading
(
reading_t
reading
,
unsigned
cacheIndex
)
{
_readingQueue
->
push
(
reading
);
_cache
[
_cacheIndex
]
=
reading
;
_cacheIndex
=
(
_cacheIndex
+
1
)
%
_cacheSize
;
//want to store absolute values here
if
(
ULLONG_MAX
-
_latestValue
.
value
<
reading
.
value
)
{
_latestValue
.
value
=
reading
.
value
-
(
ULLONG_MAX
-
_latestValue
.
value
);
}
else
{
_latestValue
.
value
+=
reading
.
value
;
}
_latestValue
.
timestamp
=
reading
.
timestamp
;
}
void
PerfSingleSensor
::
read
()
{
reading_t
reading
;
reading
.
timestamp
=
getTimestamp
();
unsigned
long
long
count
;
if
(
::
read
(
_fd
,
&
count
,
sizeof
(
long
long
))
<
0
)
{
LOG
(
error
)
<<
_name
<<
" could not read value"
;
return
;
}
if
(
count
>=
_latestValue
.
value
)
{
reading
.
value
=
count
-
_latestValue
.
value
;
}
else
{
//the counter overflow since last read
//according to perf_event_open() man-page u64 (=64bit) is used for event values
//--> unsigned long long is usually also 64bit
reading
.
value
=
count
+
(
ULLONG_MAX
-
_latestValue
.
value
);
}
#ifdef DEBUG
LOG
(
debug
)
<<
_name
<<
":
\"
"
<<
reading
.
value
<<
"
\"
"
;
#endif
storeReading
(
reading
,
_cacheIndex
);
}
void
PerfSingleSensor
::
readAsync
()
{
uint64_t
now
=
getTimestamp
();
read
();
if
(
_timer
&&
_keepRunning
)
{
uint64_t
next
=
now
+
MS_TO_NS
(
_interval
);
_timer
->
expires_at
(
timestamp2ptime
(
next
));
_pendingTasks
++
;
_timer
->
async_wait
(
std
::
bind
(
&
PerfSingleSensor
::
readAsync
,
this
));
}
_pendingTasks
--
;
}
src/sensors/perfevent/PerfSingleSensor.h
deleted
100644 → 0
View file @
7d45a2a1
/*
* PerfSingleSensor.h
*
* Created on: 11.12.2017
* Author: Micha Mueller
*/
#ifndef PERFSINGLESENSOR_H_
#define PERFSINGLESENSOR_H_
#include
"PerfAttributes.h"
#include
"PerfSensorBase.h"
#include
"../../includes/SingleSensor.h"
class
PerfSingleSensor
:
public
PerfSensorBase
,
public
PerfAttributes
,
public
SingleSensor
{
public:
PerfSingleSensor
(
const
std
::
string
&
name
);
virtual
~
PerfSingleSensor
();
void
start
()
override
;
void
stop
()
override
;
private:
void
storeReading
(
reading_t
reading
,
unsigned
cacheIndex
)
override
;
void
read
()
override
;
void
readAsync
()
override
;
};
#endif
/* PERFSINGLESENSOR_H_ */
src/sensors/perfevent/PerfeventConfigurator.cpp
View file @
f0b8f7bf
...
...
@@ -17,6 +17,9 @@
using
namespace
std
;
PerfeventConfigurator
::
PerfeventConfigurator
()
{
_groupName
=
"group"
;
_baseName
=
"counter"
;
//set up enum-maps to map string from cfgFile to an enum value defined in linux/perf_event.h
_enumType
[
"PERF_TYPE_HARDWARE"
]
=
PERF_TYPE_HARDWARE
;
_enumType
[
"PERF_TYPE_SOFTWARE"
]
=
PERF_TYPE_SOFTWARE
;
...
...
@@ -54,178 +57,133 @@ PerfeventConfigurator::PerfeventConfigurator() {
PerfeventConfigurator
::~
PerfeventConfigurator
()
{}
bool
PerfeventConfigurator
::
derivedReadConfig
(
boost
::
property_tree
::
iptree
&
cfg
)
{
//read cpu-lists for template sensors
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
sensor
,
cfg
.
get_child
(
"sensorTemplates"
))
{
if
(
STRCMP
(
sensor
,
"sensor"
))
{
if
(
!
sensor
.
second
.
empty
())
{
//check if cpus-list is given for this template sensor
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
cpus
=
sensor
.
second
.
get_child_optional
(
"cpus"
);
if
(
cpus
)
{
LOG
(
debug
)
<<
"Reading CPUs for
\"
"
<<
sensor
.
second
.
data
()
<<
"
\"
"
;
std
::
set
<
int
>
cpuVec
=
parseCpuString
(
cpus
.
get
().
data
());
_templateCpus
.
insert
(
templateCpuMap_t
::
value_type
(
sensor
.
second
.
data
(),
cpuVec
));
void
PerfeventConfigurator
::
sensorBase
(
PerfSensorBase
&
s
,
CFG_VAL
config
)
{
/*
* Custom code, as perf-event is an extra special plugin
*/
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
val
,
config
)
{
if
(
boost
::
iequals
(
val
.
first
,
"type"
))
{
enumMap_t
::
iterator
it
=
_enumType
.
find
(
val
.
second
.
data
());
if
(
it
!=
_enumType
.
end
())
{
s
.
setType
(
it
->
second
);
//LOG(debug) << " Type: " << val.second.data() << " (= " << s.getType() << ")";
}
else
{
LOG
(
warning
)
<<
" Type
\"
"
<<
val
.
second
.
data
()
<<
"
\"
not known."
;
}
}
else
if
(
boost
::
iequals
(
val
.
first
,
"config"
))
{
if
(
s
.
getType
()
==
PERF_TYPE_BREAKPOINT
)
{
//leave config zero
}
else
if
(
s
.
getType
()
==
PERF_TYPE_RAW
)
{
//read in custom hex-value
unsigned
long
config
=
stoul
(
val
.
second
.
data
(),
0
,
16
);
s
.
setConfig
(
config
);
LOG
(
debug
)
<<
" Config: Raw value: "
<<
s
.
getConfig
();
}
else
{
enumMap_t
::
iterator
it
=
_enumConfig
.
find
(
val
.
second
.
data
());
if
(
it
!=
_enumConfig
.
end
())
{
s
.
setConfig
(
it
->
second
);
//LOG(debug) << " Config: " << val.second.data() << " (= " << s.getConfig() << ")";
}
else
{
LOG
(
warning
)
<<
" Config
\"
"
<<
val
.
second
.
data
()
<<
"
\"
not known."
;
}
}
}
}
}
//read one sensor at a time
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
sensor
,
cfg
.
get_child
(
"sensors"
))
{
if
(
STRCMP
(
sensor
,
"sensor"
))
{
LOG
(
debug
)
<<
"Sensor
\"
"
<<
sensor
.
second
.
data
()
<<
"
\"
"
;
if
(
!
sensor
.
second
.
empty
())
{
PerfSingleSensor
perfSensor
(
sensor
.
second
.
data
());
void
PerfeventConfigurator
::
sensorGroup
(
PerfSensorGroup
&
s
,
CFG_VAL
config
)
{
ADD
{
//no group attributes currently
}
}
//first check if default counter is given
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
defaultC
=
sensor
.
second
.
get_child_optional
(
"default"
);
if
(
defaultC
)
{
LOG
(
debug
)
<<
" Using
\"
"
<<
defaultC
.
get
().
data
()
<<
"
\"
as default."
;
sensorMap_t
::
iterator
it
=
_templateSensors
.
find
(
defaultC
.
get
().
data
());
if
(
it
!=
_templateSensors
.
end
())
{
perfSensor
=
it
->
second
;
perfSensor
.
setName
(
sensor
.
second
.
data
());
}
else
{
LOG
(
warning
)
<<
" Template sensor
\"
"
<<
defaultC
.
get
().
data
()
<<
"
\"
not found! Using standard values."
;
bool
PerfeventConfigurator
::
readConfig
(
std
::
string
cfgPath
)
{
/*
* Custom code, as perf-event is an extra special plugin
*/
_cfgPath
=
cfgPath
;
boost
::
property_tree
::
iptree
cfg
;
boost
::
property_tree
::
read_info
(
cfgPath
,
cfg
);
//read global variables (if present overwrite those from global.conf)
readGlobal
(
cfg
);
//read groups and templates for groups
BOOST_FOREACH
(
boost
::
property_tree
::
iptree
::
value_type
&
val
,
cfg
)
{
if
(
boost
::
iequals
(
val
.
first
,
"template_"
+
_groupName
))
{
LOG
(
debug
)
<<
"Template "
<<
_groupName
<<
"
\"
"
<<
val
.
second
.
data
()
<<
"
\"
"
;
if
(
!
val
.
second
.
empty
())
{
PerfSensorGroup
*
group
=
new
PerfSensorGroup
(
val
.
second
.
data
());
if
(
readSensorGroup
(
*
group
,
val
.
second
))
{
//check if cpus-list is given for this template group
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
cpus
=
val
.
second
.
get_child_optional
(
"cpus"
);
if
(
cpus
)
{
LOG
(
debug
)
<<
"Reading CPUs for
\"
"
<<
val
.
second
.
data
()
<<
"
\"
"
;
std
::
set
<
int
>
cpuVec
=
parseCpuString
(
cpus
.
get
().
data
());
_templateCpus
.
insert
(
templateCpuMap_t
::
value_type
(
val
.
second
.
data
(),
cpuVec
));
}
}
//initialize set with cpuIDs
//default cpuSet: contains all cpuIDs
std
::
set
<
int
>
cpuSet
;
for
(
int
i
=
0
;
i
<
get_nprocs
();
i
++
)
{
cpuSet
.
insert
(
i
);
}
//check if (differing) cpus-list is given; if so, overwrite default cpuVec
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
cpus
=
sensor
.
second
.
get_child_optional
(
"cpus"
);
if
(
cpus
)
{
//cpu list given
cpuSet
=
parseCpuString
(
cpus
.
get
().
data
());
}
else
if
(
defaultC
)
{
//cpu list not given, but perhaps template counter has one
templateCpuMap_t
::
iterator
itC
=
_templateCpus
.
find
(
defaultC
.
get
().
data
());
if
(
itC
!=
_templateCpus
.
end
())
{
cpuSet
=
itC
->
second
;
auto
ret
=
_templateSensorGroups
.
insert
(
std
::
pair
<
std
::
string
,
PerfSensorGroup
*>
(
val
.
second
.
data
(),
group
));
if
(
!
ret
.
second
)
{
LOG
(
warning
)
<<
"Template "
<<
_groupName
<<
" "
<<
val
.
second
.
data
()
<<
" already exists! Omitting..."
;
}
}
else
{
LOG
(
warning
)
<<
"Template "
<<
_groupName
<<
"
\"
"
<<
val
.
second
.
data
()
<<
"
\"
has bad values! Ignoring..."
;
}
}
}
else
if
(
boost
::
iequals
(
val
.
first
,
_groupName
))
{
LOG
(
debug
)
<<
_groupName
<<
"
\"
"
<<
val
.
second
.
data
()
<<
"
\"
"
;
if
(
!
val
.
second
.
empty
())
{
PerfSensorGroup
group
(
val
.
second
.
data
());
if
(
readSensorGroup
(
group
,
val
.
second
))
{
//now for the cpus...
//initialize set with cpuIDs
//default cpuSet: contains all cpuIDs
std
::
set
<
int
>
cpuSet
;
for
(
int
i
=
0
;
i
<
get_nprocs
();
i
++
)
{
cpuSet
.
insert
(
i
);
}
//check if (differing) cpus-list is given; if so, overwrite default cpuVec
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
cpus
=
val
.
second
.
get_child_optional
(
"cpus"
);
if
(
cpus
)
{
//cpu list given
cpuSet
=
parseCpuString
(
cpus
.
get
().
data
());
}
else
{
//cpu list not given, but perhaps template counter has one
boost
::
optional
<
boost
::
property_tree
::
iptree
&>
def
=
val
.
second
.
get_child_optional
(
"default"
);
if
(
def
)
{
templateCpuMap_t
::
iterator
itC
=
_templateCpus
.
find
(
def
.
get
().
data
());
if
(
itC
!=
_templateCpus
.
end
())
{
cpuSet
=
itC
->
second
;
}
}
}
//read remaining values
if
(
readSingleSensor
(
perfSensor
,
sensor
.
second
))
{
//create distinct perfCounter and mqttSuffix per CPU
string
startMqtt
=
perfSensor
.
getMqtt
();
string
startMqtt
=
group
.
getMqttPart
();
//customize perfCounter for every CPU
//customize perfCounter
Group
for every CPU
for
(
auto
i
:
cpuSet
)
{
PerfSingleSensor
*
perfS
=
new
PerfSingleSensor
(
sensor
.
second
.
data
());
*
perfS
=
perfSensor
;
PerfSensorGroup
*
perfSG
=
new
PerfSensorGroup
(
group
);
string
incMqtt
=
increaseMqtt
(
startMqtt
,
i
);
perfS
->
setName
(
perfS
->
getName
()
+
std
::
to_string
(
i
));
perfS
->
setCpuId
(
i
);
perfS
->
setMqtt
(
_mqttPrefix
+
incMqtt
);
LOG
(
debug
)
<<
" CPU "
<<
perfS
->
getCpuId
()
<<
" using MQTT-Topic "
<<
perfS
->
getMqtt
();
_sensors
.
push_back
(
perfS
);