Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F61630884
perf_counters_gtest.cc
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, May 7, 23:01
Size
6 KB
Mime Type
text/x-c
Expires
Thu, May 9, 23:01 (2 d)
Engine
blob
Format
Raw Data
Handle
17537754
Attached To
R12667 gbench-stream
perf_counters_gtest.cc
View Options
#include <thread>
#include "../src/perf_counters.h"
#include "gtest/gtest.h"
#ifndef GTEST_SKIP
struct
MsgHandler
{
void
operator
=
(
std
::
ostream
&
)
{}
};
#define GTEST_SKIP() return MsgHandler() = std::cout
#endif
using
benchmark
::
internal
::
PerfCounters
;
using
benchmark
::
internal
::
PerfCountersMeasurement
;
using
benchmark
::
internal
::
PerfCounterValues
;
namespace
{
const
char
kGenericPerfEvent1
[]
=
"CYCLES"
;
const
char
kGenericPerfEvent2
[]
=
"BRANCHES"
;
const
char
kGenericPerfEvent3
[]
=
"INSTRUCTIONS"
;
TEST
(
PerfCountersTest
,
Init
)
{
EXPECT_EQ
(
PerfCounters
::
Initialize
(),
PerfCounters
::
kSupported
);
}
TEST
(
PerfCountersTest
,
OneCounter
)
{
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Performance counters not supported.
\n
"
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
EXPECT_TRUE
(
PerfCounters
::
Create
({
kGenericPerfEvent1
}).
IsValid
());
}
TEST
(
PerfCountersTest
,
NegativeTest
)
{
if
(
!
PerfCounters
::
kSupported
)
{
EXPECT_FALSE
(
PerfCounters
::
Initialize
());
return
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
EXPECT_FALSE
(
PerfCounters
::
Create
({}).
IsValid
());
EXPECT_FALSE
(
PerfCounters
::
Create
({
""
}).
IsValid
());
EXPECT_FALSE
(
PerfCounters
::
Create
({
"not a counter name"
}).
IsValid
());
{
EXPECT_TRUE
(
PerfCounters
::
Create
({
kGenericPerfEvent1
,
kGenericPerfEvent2
,
kGenericPerfEvent3
})
.
IsValid
());
}
EXPECT_FALSE
(
PerfCounters
::
Create
({
kGenericPerfEvent2
,
""
,
kGenericPerfEvent1
})
.
IsValid
());
EXPECT_FALSE
(
PerfCounters
::
Create
({
kGenericPerfEvent3
,
"not a counter name"
,
kGenericPerfEvent1
})
.
IsValid
());
{
EXPECT_TRUE
(
PerfCounters
::
Create
({
kGenericPerfEvent1
,
kGenericPerfEvent2
,
kGenericPerfEvent3
})
.
IsValid
());
}
EXPECT_FALSE
(
PerfCounters
::
Create
({
kGenericPerfEvent1
,
kGenericPerfEvent2
,
kGenericPerfEvent3
,
"MISPREDICTED_BRANCH_RETIRED"
})
.
IsValid
());
}
TEST
(
PerfCountersTest
,
Read1Counter
)
{
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Test skipped because libpfm is not supported.
\n
"
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
auto
counters
=
PerfCounters
::
Create
({
kGenericPerfEvent1
});
EXPECT_TRUE
(
counters
.
IsValid
());
PerfCounterValues
values1
(
1
);
EXPECT_TRUE
(
counters
.
Snapshot
(
&
values1
));
EXPECT_GT
(
values1
[
0
],
0
);
PerfCounterValues
values2
(
1
);
EXPECT_TRUE
(
counters
.
Snapshot
(
&
values2
));
EXPECT_GT
(
values2
[
0
],
0
);
EXPECT_GT
(
values2
[
0
],
values1
[
0
]);
}
TEST
(
PerfCountersTest
,
Read2Counters
)
{
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Test skipped because libpfm is not supported.
\n
"
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
auto
counters
=
PerfCounters
::
Create
({
kGenericPerfEvent1
,
kGenericPerfEvent2
});
EXPECT_TRUE
(
counters
.
IsValid
());
PerfCounterValues
values1
(
2
);
EXPECT_TRUE
(
counters
.
Snapshot
(
&
values1
));
EXPECT_GT
(
values1
[
0
],
0
);
EXPECT_GT
(
values1
[
1
],
0
);
PerfCounterValues
values2
(
2
);
EXPECT_TRUE
(
counters
.
Snapshot
(
&
values2
));
EXPECT_GT
(
values2
[
0
],
0
);
EXPECT_GT
(
values2
[
1
],
0
);
}
TEST
(
PerfCountersTest
,
ReopenExistingCounters
)
{
// The test works (i.e. causes read to fail) for the assumptions
// about hardware capabilities (i.e. small number (3-4) hardware
// counters) at this date.
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Test skipped because libpfm is not supported.
\n
"
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
std
::
vector
<
PerfCounters
>
counters
;
counters
.
reserve
(
6
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
counters
.
push_back
(
PerfCounters
::
Create
({
kGenericPerfEvent1
}));
PerfCounterValues
values
(
1
);
EXPECT_TRUE
(
counters
[
0
].
Snapshot
(
&
values
));
EXPECT_FALSE
(
counters
[
4
].
Snapshot
(
&
values
));
EXPECT_FALSE
(
counters
[
5
].
Snapshot
(
&
values
));
}
TEST
(
PerfCountersTest
,
CreateExistingMeasurements
)
{
// The test works (i.e. causes read to fail) for the assumptions
// about hardware capabilities (i.e. small number (3-4) hardware
// counters) at this date,
// the same as previous test ReopenExistingCounters.
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Test skipped because libpfm is not supported.
\n
"
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
std
::
vector
<
PerfCountersMeasurement
>
perf_counter_measurements
;
std
::
vector
<
std
::
pair
<
std
::
string
,
double
>>
measurements
;
perf_counter_measurements
.
reserve
(
10
);
for
(
int
i
=
0
;
i
<
10
;
i
++
)
perf_counter_measurements
.
emplace_back
(
std
::
vector
<
std
::
string
>
{
kGenericPerfEvent1
});
perf_counter_measurements
[
0
].
Start
();
EXPECT_TRUE
(
perf_counter_measurements
[
0
].
Stop
(
measurements
));
measurements
.
clear
();
perf_counter_measurements
[
8
].
Start
();
EXPECT_FALSE
(
perf_counter_measurements
[
8
].
Stop
(
measurements
));
measurements
.
clear
();
perf_counter_measurements
[
9
].
Start
();
EXPECT_FALSE
(
perf_counter_measurements
[
9
].
Stop
(
measurements
));
}
size_t
do_work
()
{
size_t
res
=
0
;
for
(
size_t
i
=
0
;
i
<
100000000
;
++
i
)
res
+=
i
*
i
;
return
res
;
}
void
measure
(
size_t
threadcount
,
PerfCounterValues
*
values1
,
PerfCounterValues
*
values2
)
{
BM_CHECK_NE
(
values1
,
nullptr
);
BM_CHECK_NE
(
values2
,
nullptr
);
std
::
vector
<
std
::
thread
>
threads
(
threadcount
);
auto
work
=
[
&
]()
{
BM_CHECK
(
do_work
()
>
1000
);
};
// We need to first set up the counters, then start the threads, so the
// threads would inherit the counters. But later, we need to first destroy the
// thread pool (so all the work finishes), then measure the counters. So the
// scopes overlap, and we need to explicitly control the scope of the
// threadpool.
auto
counters
=
PerfCounters
::
Create
({
kGenericPerfEvent1
,
kGenericPerfEvent3
});
for
(
auto
&
t
:
threads
)
t
=
std
::
thread
(
work
);
counters
.
Snapshot
(
values1
);
for
(
auto
&
t
:
threads
)
t
.
join
();
counters
.
Snapshot
(
values2
);
}
TEST
(
PerfCountersTest
,
MultiThreaded
)
{
if
(
!
PerfCounters
::
kSupported
)
{
GTEST_SKIP
()
<<
"Test skipped because libpfm is not supported."
;
}
EXPECT_TRUE
(
PerfCounters
::
Initialize
());
PerfCounterValues
values1
(
2
);
PerfCounterValues
values2
(
2
);
measure
(
2
,
&
values1
,
&
values2
);
std
::
vector
<
double
>
D1
{
static_cast
<
double
>
(
values2
[
0
]
-
values1
[
0
]),
static_cast
<
double
>
(
values2
[
1
]
-
values1
[
1
])};
measure
(
4
,
&
values1
,
&
values2
);
std
::
vector
<
double
>
D2
{
static_cast
<
double
>
(
values2
[
0
]
-
values1
[
0
]),
static_cast
<
double
>
(
values2
[
1
]
-
values1
[
1
])};
// Some extra work will happen on the main thread - like joining the threads
// - so the ratio won't be quite 2.0, but very close.
EXPECT_GE
(
D2
[
0
],
1.9
*
D1
[
0
]);
EXPECT_GE
(
D2
[
1
],
1.9
*
D1
[
1
]);
}
}
// namespace
Event Timeline
Log In to Comment