mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
start moving algorithm in
This commit is contained in:
30
userland/algorithm/set/generate_io
Executable file
30
userland/algorithm/set/generate_io
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import random
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
import common
|
||||
|
||||
# Handle CLI arguments.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--min', type=int, default=0)
|
||||
parser.add_argument('--max', type=int, default=(2**32 - 1))
|
||||
parser.add_argument('--seed', type=int)
|
||||
parser.add_argument('--size', type=int, default=1000000)
|
||||
parser.add_argument('--unique', type=bool, default=True,
|
||||
help='if True, remove duplicates from the expected output')
|
||||
args = parser.parse_args()
|
||||
random.seed(args.seed)
|
||||
input_data = common.LkmcList()
|
||||
for i in range(args.size):
|
||||
input_data.append(random.randint(args.min, args.max))
|
||||
with open('tmp.i', 'w') as i:
|
||||
i.write(str(input_data) + '\n')
|
||||
if args.unique:
|
||||
input_data = common.LkmcList(set(input_data))
|
||||
input_data.sort()
|
||||
with open('tmp.e', 'w') as e:
|
||||
e.write(str(input_data) + '\n')
|
||||
@@ -18,9 +18,10 @@
|
||||
#include <lkmc/m5ops.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Variables.
|
||||
typedef uint64_t T;
|
||||
#if LKMC_ALGORITHM_SET_STD_PRIORITY_QUEUE
|
||||
std::priority_queue<T> set;
|
||||
std::priority_queue<T, std::vector<T>, std::greater<T>> set;
|
||||
#endif
|
||||
#if LKMC_ALGORITHM_SET_STD_SET
|
||||
std::set<T> set;
|
||||
@@ -28,57 +29,59 @@ int main(int argc, char **argv) {
|
||||
#if LKMC_ALGORITHM_SET_STD_UNORDERED_SET
|
||||
std::unordered_set<T> set;
|
||||
#endif
|
||||
std::vector<T> randoms;
|
||||
std::vector<T> input;
|
||||
size_t i, j = 0, n, granule, base;
|
||||
unsigned int seed;
|
||||
#ifndef LKMC_M5OPS_ENABLE
|
||||
std::vector<std::chrono::nanoseconds::rep> dts;
|
||||
std::vector<decltype(base)> bases;
|
||||
using clk = std::chrono::high_resolution_clock;
|
||||
decltype(clk::now()) start, end;
|
||||
#endif
|
||||
|
||||
// CLI arguments.
|
||||
//
|
||||
// Save the clock time every `granule` loops.
|
||||
//
|
||||
// The magic value 0 means that a single time for the entire
|
||||
// run is printed, therefore accounting for the full run time.
|
||||
//
|
||||
// Otherwise, must be a divisor of the input size.
|
||||
//
|
||||
// Default value: 0
|
||||
if (argc > 1) {
|
||||
n = std::stoi(argv[1]);
|
||||
granule = std::stoll(argv[1]);
|
||||
} else {
|
||||
n = 10;
|
||||
granule = 0;
|
||||
}
|
||||
if (argc > 2) {
|
||||
granule = std::stoi(argv[2]);
|
||||
} else {
|
||||
granule = 1;
|
||||
|
||||
// Read input from stdin.
|
||||
std::string str;
|
||||
while (std::getline(std::cin, str)) {
|
||||
if (str == "")
|
||||
break;
|
||||
input.push_back(std::stoll(str));
|
||||
}
|
||||
if (argc > 3) {
|
||||
seed = std::stoi(argv[3]);
|
||||
} else {
|
||||
seed = std::random_device()();
|
||||
n = input.size();
|
||||
if (granule == 0) {
|
||||
granule = n;
|
||||
}
|
||||
|
||||
// Action.
|
||||
for (i = 0; i < n; ++i) {
|
||||
randoms.push_back(i);
|
||||
}
|
||||
std::shuffle(randoms.begin(), randoms.end(), std::mt19937(seed));
|
||||
for (i = 0; i < n / granule; ++i) {
|
||||
#ifndef LKMC_M5OPS_ENABLE
|
||||
using clk = std::chrono::high_resolution_clock;
|
||||
decltype(clk::now()) start, end;
|
||||
#endif
|
||||
base = i * granule;
|
||||
#ifdef LKMC_M5OPS_ENABLE
|
||||
LKMC_M5OPS_RESETSTATS;
|
||||
#else
|
||||
#ifndef LKMC_M5OPS_ENABLE
|
||||
start = clk::now();
|
||||
#endif
|
||||
for (j = 0; j < granule; ++j) {
|
||||
#endif
|
||||
LKMC_M5OPS_RESETSTATS;
|
||||
#if LKMC_ALGORITHM_SET_STD_PRIORITY_QUEUE
|
||||
set.emplace(randoms[base + j]);
|
||||
set.emplace(input[base + j]);
|
||||
#else
|
||||
set.insert(randoms[base + j]);
|
||||
set.insert(input[base + j]);
|
||||
#endif
|
||||
#ifdef LKMC_M5OPS_ENABLE
|
||||
LKMC_M5OPS_DUMPSTATS;
|
||||
#else
|
||||
LKMC_M5OPS_DUMPSTATS;
|
||||
}
|
||||
#ifndef LKMC_M5OPS_ENABLE
|
||||
end = clk::now();
|
||||
auto dt = (end - start) / granule;
|
||||
bases.push_back(base);
|
||||
@@ -87,8 +90,26 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
// Report results.
|
||||
std::cout << "output" << std::endl;
|
||||
#if LKMC_ALGORITHM_SET_STD_PRIORITY_QUEUE
|
||||
// Print priority queue without duplicates.
|
||||
T last_val = set.top();
|
||||
std::cout << last_val << std::endl;
|
||||
set.pop();
|
||||
while (!set.empty()) {
|
||||
const auto& val = set.top();
|
||||
if (val != last_val)
|
||||
std::cout << val << std::endl;
|
||||
last_val = val;
|
||||
set.pop();
|
||||
}
|
||||
#else
|
||||
for (const auto& item : set) {
|
||||
std::cout << item << std::endl;
|
||||
}
|
||||
#endif
|
||||
std::cout << std::endl;
|
||||
#ifndef LKMC_M5OPS_ENABLE
|
||||
// Output.
|
||||
std::cout << "times" << std::endl;
|
||||
auto bases_it = bases.begin();
|
||||
auto dts_it = dts.begin();
|
||||
@@ -99,17 +120,5 @@ int main(int argc, char **argv) {
|
||||
bases_it++;
|
||||
dts_it++;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "output" << std::endl;
|
||||
#if LKMC_ALGORITHM_SET_STD_PRIORITY_QUEUE
|
||||
while (!set.empty()) {
|
||||
std::cout << set.top() << std::endl;
|
||||
set.pop();
|
||||
}
|
||||
#else
|
||||
for (const auto& item : set) {
|
||||
std::cout << item << std::endl;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
40
userland/algorithm/set/parse_output
Executable file
40
userland/algorithm/set/parse_output
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
import common
|
||||
|
||||
data = common.LkmcOrderedDict()
|
||||
|
||||
# Parse
|
||||
|
||||
output = common.LkmcList()
|
||||
next(sys.stdin)
|
||||
for line in sys.stdin:
|
||||
line = line.rstrip()
|
||||
if line == '':
|
||||
break
|
||||
output.append(int(line))
|
||||
data['output'] = output
|
||||
|
||||
times = common.LkmcList()
|
||||
next(sys.stdin)
|
||||
for line in sys.stdin:
|
||||
line = line.rstrip()
|
||||
if line == '':
|
||||
break
|
||||
times.append(common.LkmcList([int(i) for i in line.split(' ')], oneline=True))
|
||||
data['times'] = times
|
||||
|
||||
# Handle CLI arguments.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('key', nargs='?')
|
||||
args = parser.parse_args()
|
||||
if args.key:
|
||||
print(data[args.key])
|
||||
else:
|
||||
print(data)
|
||||
3
userland/algorithm/set/test_data/3.e
Normal file
3
userland/algorithm/set/test_data/3.e
Normal file
@@ -0,0 +1,3 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
userland/algorithm/set/test_data/3.i
Normal file
3
userland/algorithm/set/test_data/3.i
Normal file
@@ -0,0 +1,3 @@
|
||||
1
|
||||
2
|
||||
0
|
||||
4
userland/algorithm/set/test_data/4.e
Normal file
4
userland/algorithm/set/test_data/4.e
Normal file
@@ -0,0 +1,4 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
userland/algorithm/set/test_data/4.i
Normal file
4
userland/algorithm/set/test_data/4.i
Normal file
@@ -0,0 +1,4 @@
|
||||
1
|
||||
3
|
||||
2
|
||||
0
|
||||
5
userland/algorithm/set/test_data/5.e
Normal file
5
userland/algorithm/set/test_data/5.e
Normal file
@@ -0,0 +1,5 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
userland/algorithm/set/test_data/5.i
Normal file
5
userland/algorithm/set/test_data/5.i
Normal file
@@ -0,0 +1,5 @@
|
||||
1
|
||||
4
|
||||
0
|
||||
2
|
||||
3
|
||||
8
userland/algorithm/set/test_data/8.e
Normal file
8
userland/algorithm/set/test_data/8.e
Normal file
@@ -0,0 +1,8 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
userland/algorithm/set/test_data/8.i
Normal file
8
userland/algorithm/set/test_data/8.i
Normal file
@@ -0,0 +1,8 @@
|
||||
4
|
||||
5
|
||||
6
|
||||
2
|
||||
1
|
||||
3
|
||||
0
|
||||
7
|
||||
@@ -1,98 +0,0 @@
|
||||
// https://cirosantilli.com/linux-kernel-module-cheat#cpp-multithreading
|
||||
//
|
||||
// The non-atomic counters have undefined values which get printed:
|
||||
// they are extremely likely to be less than the correct value due to
|
||||
// race conditions on the data read and update of the ++.
|
||||
//
|
||||
// The atomic counters have defined values, and are asserted
|
||||
//
|
||||
// Atomic operations are more restricted than mutex as they can
|
||||
// only protect a few operations on integers.
|
||||
//
|
||||
// But when they can be used, they can be much more efficient than mutees.
|
||||
//
|
||||
// On GCC 4.8 x86-64, using atomic offered a 5x peformance improvement
|
||||
// over the same program with mutexes.
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
std::atomic_ulong my_atomic_ulong(0);
|
||||
unsigned long my_non_atomic_ulong = 0;
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
unsigned long my_arch_atomic_ulong = 0;
|
||||
unsigned long my_arch_non_atomic_ulong = 0;
|
||||
#endif
|
||||
size_t niters;
|
||||
|
||||
void threadMain() {
|
||||
for (size_t i = 0; i < niters; ++i) {
|
||||
my_atomic_ulong++;
|
||||
my_non_atomic_ulong++;
|
||||
#if defined(__x86_64__)
|
||||
__asm__ __volatile__ (
|
||||
"incq %0;"
|
||||
: "+m" (my_arch_non_atomic_ulong)
|
||||
:
|
||||
:
|
||||
);
|
||||
// https://cirosantilli.com/linux-kernel-module-cheat#x86-lock-prefix
|
||||
__asm__ __volatile__ (
|
||||
"lock;"
|
||||
"incq %0;"
|
||||
: "+m" (my_arch_atomic_ulong)
|
||||
:
|
||||
:
|
||||
);
|
||||
#elif defined(__aarch64__)
|
||||
__asm__ __volatile__ (
|
||||
"add %0, %0, 1;"
|
||||
: "+r" (my_arch_non_atomic_ulong)
|
||||
:
|
||||
:
|
||||
);
|
||||
// https://cirosantilli.com/linux-kernel-module-cheat#arm-lse
|
||||
__asm__ __volatile__ (
|
||||
"ldadd %[inc], xzr, [%[addr]];"
|
||||
: "=m" (my_arch_atomic_ulong)
|
||||
: [inc] "r" (1),
|
||||
[addr] "r" (&my_arch_atomic_ulong)
|
||||
:
|
||||
);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if __cplusplus >= 201103L
|
||||
size_t nthreads;
|
||||
if (argc > 1) {
|
||||
nthreads = std::stoull(argv[1], NULL, 0);
|
||||
} else {
|
||||
nthreads = 2;
|
||||
}
|
||||
if (argc > 2) {
|
||||
niters = std::stoull(argv[2], NULL, 0);
|
||||
} else {
|
||||
niters = 10;
|
||||
}
|
||||
std::vector<std::thread> threads(nthreads);
|
||||
for (size_t i = 0; i < nthreads; ++i)
|
||||
threads[i] = std::thread(threadMain);
|
||||
for (size_t i = 0; i < nthreads; ++i)
|
||||
threads[i].join();
|
||||
assert(my_atomic_ulong.load() == nthreads * niters);
|
||||
// We can also use the atomics direclty through `operator T` conversion.
|
||||
assert(my_atomic_ulong == my_atomic_ulong.load());
|
||||
std::cout << "my_non_atomic_ulong " << my_non_atomic_ulong << std::endl;
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
assert(my_arch_atomic_ulong == nthreads * niters);
|
||||
std::cout << "my_arch_non_atomic_ulong " << my_arch_non_atomic_ulong << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user