METIS: different results on different OS - c

This C program calls METIS to partition a mesh.
Edit: New version of the C program taking into account comments of WeatherVane and PaulOgilvie.
On my GNU/Linux I get the results:
objval: 14
epart: 0 0 0 0 0 1 2 2 1 0 0 1 2 2 1 2 2 1
npart: 0 0 0 2 0 0 1 1 2 2 2 1 2 2 1 1
8
while on my OSX I get:
objval: 17
epart: 0 1 1 0 1 0 2 2 0 1 1 1 2 2 1 2 2 0
npart: 0 1 1 1 0 1 0 1 2 2 2 0 2 2 0 0
8
What causes the results to be different?
How to fix it, I mean, always get the same results whatever the OS/architecture/compiler is?
Note: idx_t is int64_t, which is long on my GNU/Linux, but long long on my OSX.
My GNU/Linux
$ cat /etc/issue
Ubuntu 12.04.4 LTS \n \l
$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ uname -s -r -v -p -i -o
Linux 3.5.0-45-generic #68~precise1-Ubuntu SMP Wed Dec 4 16:18:46 UTC 2013 x86_64 x86_64 GNU/Linux
My OSX
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.9.5
BuildVersion: 13F34
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
$ uname -m -p -r -s -v
Darwin 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64 i386
METIS installation
METIS version is 5.1.0
I have installed METIS with miniconda.
The packages are here
(files linux-64/metis-5.1.0-0.tar.bz2 and osx-64/metis-5.1.0-2.tar.bz2).
These packages have been built with this recipe.

METIS make use of pseudo-random numbers.
The pseudo-random numbers are generated by GKlib functions. (GKlib is embedded inside METIS tarbarlls).
By default, GKlib uses the rand function from the C standard library, which may generates different number on different platforms. (see: Consistent pseudo-random numbers across platforms).
But GKlib can also be compiled with the flag -DUSE_GKRAND. Instead of using the rand function, it uses its own, which always give the same random numbers of different plateforms.
Compiling with -DUSE_GKRAND the C code in the function give the same results on my GNU/Linux and on my OSX:
objval: 18
epart: 0 0 0 2 1 1 2 2 1 0 0 1 0 1 1 2 2 1
npart: 0 0 0 0 2 0 1 1 2 1 2 1 2 2 1 1
8
I've used this conda recipe to build METIS.

Related

Treating files by using Julia language

I'm a Julia beginner (scripting beginner too).
I have a text file which consists in 4 columns:
1 5.4 9.5 19.5
2 5.4 9.4 20.6
2 6.2 9.6 18.3
1 9.1 0.5 17.2
2 8.5 1.4 19.6
2 8.4 0.6 24.1
etc.
I have no idea how in Julia I can replace certain values in the rows or add a new one according to a existing column pattern 122 122. For example I would like to add the column with letter C and O (C when is 1 in the first column and O when is 2). I would like to add new column after the one with C and O where the pattern 1 2 2 is designated by number 4 and next by number 5. This is how I imagine the result:
C 4 1 5.4 9.5 19.5
O 4 2 5.4 9.4 20.6
O 4 2 6.2 9.6 18.3
C 5 1 9.1 0.5 17.2
O 5 2 8.5 1.4 19.6
O 5 2 8.4 0.6 24.1
Thank you for your help in advance.
Kasia.
String processing is fairly straightforward in Julia. You might write a function that takes an input and output filename as follows:
function munge_file(in::AbstractString, out::AbstractString)
# open the output file for writing
open(out, "w") do out_io
# open the input file for reading
open(in, "r") do in_io
# and process the contents
munge_file(in_io, out_io)
end
end
end
Now, the inner call to munge_file will have to do the actual work (this isn't particularly optimized, but should very straightforward):
function munge_file(input::IO, io::IO = IOBuffer())
# initialize the pattern index
pattern_index = 3
# iterate over each line of the input
for line in eachline(input)
# skip empty lines
isempty(line) && continue
# split the current line into parts
parts = split(line, ' ')
# this line doesn't conform to the specified input pattern
# might be better to throw an error here
length(parts) == 4 || continue
# this line starts a new pattern if the first character is a 1
is_start = parse(Int, parts[1]) == 1
# increment the counter (for the second output column)
pattern_index += is_start
# first column depends on whether a 1 2 2 pattern starts here or not
print(io, is_start ? 'C' : 'O')
print(io, ' ')
# print the pattern counter
print(io, pattern_index)
print(io, ' ')
# print the original line
println(io, line)
end
return io
end
Using the code in the REPL produces the expected output:
shell> cat input.txt
1 5.4 9.5 19.5
2 5.4 9.4 20.6
2 6.2 9.6 18.3
1 9.1 0.5 17.2
2 8.5 1.4 19.6
2 8.4 0.6 24.1
julia> munge_file("input.txt", "output.txt")
IOStream(<file output.txt>)
shell> cat output.txt
C 4 1 5.4 9.5 19.5
O 4 2 5.4 9.4 20.6
O 4 2 6.2 9.6 18.3
C 5 1 9.1 0.5 17.2
O 5 2 8.5 1.4 19.6
O 5 2 8.4 0.6 24.1
Assuming your file is input.txt you could do:
open("output.txt","w") do f
println.(Ref(f),replace.(replace.(readlines("input.txt"),r"^1 "=>"C "), r"^2 "=>"O "))
end;
Dots (.) in the above code vectorize it so functions work on vectors rather than scalars. The replace function takes a String, regular expression and new value. ^ in regular expression means "line starts with".

GDB pid changes when connected automatically and quit

I am trying to attach an existing process, run some commands and print the required information. However, when I do it, I see that the PID of the process is changed (with killed) command being displayed.
Code
1 #include <iostream>
2 #include <unistd.h>
3 using namespace std;
4
5
6 int main()
7 {
8 do
9 {
10 static int s = 100;
11 s = s+1;
12 sleep (3);
13 } while(1);
14 return 0;
15 }
16
GDB commands
> cat /tmp/command.txt
set pagination off
set logging file /home/testgrp/gdb.txt
set logging on
b sample.cc:11
commands 1
p s
end
run 1
quit
Output
root#198.18.81.198:/desktop/user1/workspace# ps -eaf | grep out
root 16724 8877 0 08:25 pts/1 00:00:00 grep --color=auto out
root#198.18.81.198:/desktop/user1/workspace# cat /home/testgrp/gdb.txt
cat: /home/testgrp/gdb.txt: No such file or directory
root#198.18.81.198:/desktop/user1/workspace# ./a.out &
[1] 16762
root#198.18.81.198:/desktop/user1/workspace# gdb --batch-silent -x=/tmp/command.txt -p 16762
[1]+ Killed ./a.out
root#198.18.81.198:/desktop/user1/workspace# ps -eaf | grep out
root 16805 1 0 08:25 pts/1 00:00:00 /desktop/user1/workspace/a.out 1
root 16823 8877 0 08:25 pts/1 00:00:00 grep --color=auto out
root#198.18.81.198:/desktop/user1/workspace# cat /home/testgrp/gdb.txt
Breakpoint 1 at 0x400711: file sample.cc, line 11.
$1 = 100
A debugging session is active.
Inferior 1 [process 16805] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
Question
How do I get the required information without changing the PID of the process?
More importantly, why does the pid change and previous PID is killed
Appendix
GDB version
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2aka8.0.1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
in the last two lines of your gdb scripts
run 1
quit
"run 1" will restart the program it is debugging with argument "1". by default, it should ask you to confirm restart or not.But you have an argument "--batch-silent" when you starting gdb. so your process restart without message.
delete "--batch-silent" and last 2 lines of your gdb script then you can break and debug.
"b sample.cc:11" will stop in system function sleep, you can change it to other line if you feel confuse . (I recommend you to read some simpler demos before using gdb,so many cmd will let beginner feel confuse)

A specific application doesn't recognize a DLL entry point

I have something weird...
I am trying to do a proxy DLL for an old game (based on LithTech engine, abandonware, Windows 98 application), so I used wrappit, made the DLL, made it compiling, but... Well...
The DLL itself seems to be OK. At least the DllMain gets executed when testing with LOADDLL from OllyDbg...
But when I insert it into the game folder instead of the original DLL, it loads the DLL, and then it doesn't execute the DLL entry point DllMain! In some builds (Visual Studio 2005) it just says nothing. In other builds (Visual Studio 2010) it raises the c0000139 exception (which is "Entry point not found"). But how can it be that entry point is not found when it loads fine with LOADDLL in ollydbg, which means that the entry oint is in place?
Please help me!
UPD:
Posting the dumpbin /exports output:
The original DLL:
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file IMUSIC25_.DLL
File Type: DLL
Section contains the following exports for IMUSIC25.DLL
00000000 characteristics
33713027 time date stamp Thu May 08 05:45:11 1997
0.00 version
1 ordinal base
29 number of functions
29 number of names
ordinal hint RVA name
6 0 0000FD8B DllCanUnloadNow
7 1 0000FDF9 DllGetClassObject
8 2 0000FD85 DllRegisterServer
9 3 0000FD88 DllUnregisterServer
1 4 000105BD _AllocAAEngine2#8
2 5 00010507 _AllocAAEngine#4
3 6 00007101 _AllocAALoader#4
4 7 000074FC _AllocAALoaderLite#4
5 8 00010675 _AllocAAMIDIIn#4
10 9 000106A1 _GetFinalMIDISink#4
11 A 0001127F _LoadBandFile#12
12 B 000115F9 _LoadMotifFile#12
13 C 00011601 _LoadPatternFile#12
14 D 0001123C _LoadPersonalityByName#12
15 E 000111F9 _LoadPersonalityFile#12
16 F 000118F7 _LoadPersonalityFromMemory#12
17 10 0001131E _LoadSectionFile#12
18 11 000114BB _LoadSongFile#12
19 12 000111B6 _LoadStyleByName#12
20 13 00011173 _LoadStyleFile#12
21 14 0001182C _LoadStyleFromMemory#12
22 15 0001155A _LoadTemplateFile#12
23 16 000102B1 _MusicEngineSimpleInit95#12
24 17 00010497 _MusicEngineSimpleInit#12
25 18 00010066 _MusicEngineSimpleInitNT#12
26 19 000119C2 _Panic#4
27 1A 00011465 _SaveSectionAsMIDIFile#8
28 1B 000113E1 _SaveSectionFile#8
29 1C 00010692 _SetAADebug#4
Summary
4000 .data
1000 .idata
1000 .rdata
2000 .reloc
1000 .rsrc
1B000 .text
My crafted DLL:
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file IMUSIC25.DLL
File Type: DLL
Section contains the following exports for imusic25.dll
00000000 characteristics
52F816DB time date stamp Mon Feb 10 04:01:31 2014
0.00 version
1 ordinal base
30 number of functions
30 number of names
ordinal hint RVA name
6 0 00001020 DllCanUnloadNow = ___E__0__#0
7 1 00001030 DllGetClassObject = ___E__1__#0
8 2 00001040 DllRegisterServer = ___E__2__#0
9 3 00001050 DllUnregisterServer = ___E__3__#0
2 4 00001060 _AllocAAEngine = ___E__5__#0
1 5 00001130 _AllocAAEngine2 = ___E__4__#0
3 6 00001070 _AllocAALoader = ___E__6__#0
4 7 00001080 _AllocAALoaderLite = ___E__7__#0
5 8 00001090 _AllocAAMIDIIn = ___E__8__#0
30 9 00001000 _DllMain#12 = _DllMain#12
10 A 000010A0 _GetFinalMIDISink = ___E__9__#0
11 B 000010B0 _LoadBandFile = ___E__10__#0
12 C 000010C0 _LoadMotifFile = ___E__11__#0
13 D 000010D0 _LoadPatternFile = ___E__12__#0
14 E 000010E0 _LoadPersonalityByName = ___E__13__#0
15 F 000010F0 _LoadPersonalityFile = ___E__14__#0
16 10 00001100 _LoadPersonalityFromMemory = ___E__15__#0
17 11 00001130 _LoadSectionFile = ___E__4__#0
18 12 00001110 _LoadSongFile = ___E__17__#0
19 13 00001120 _LoadStyleByName = ___E__18__#0
20 14 00001130 _LoadStyleFile = ___E__4__#0
21 15 00001150 _LoadStyleFromMemory = ___E__20__#0
22 16 00001160 _LoadTemplateFile = ___E__21__#0
24 17 00001180 _MusicEngineSimpleInit = ___E__23__#0
23 18 00001170 _MusicEngineSimpleInit95 = ___E__22__#0
25 19 00001190 _MusicEngineSimpleInitNT = ___E__24__#0
26 1A 000011A0 _Panic = ___E__25__#0
27 1B 000011B0 _SaveSectionAsMIDIFile = ___E__26__#0
28 1C 000011C0 _SaveSectionFile = ___E__27__#0
29 1D 000011D0 _SetAADebug = ___E__28__#0
Summary
1000 .data
1000 .rdata
1000 .rsrc
1000 .text
UPD: I checked the "GetLastError" on the failing LoadLibraryA call - it is 0x1E7 (487) - ERROR_INVALID_ADDRESS
Well, I managed to fix that by changing the definition of the functions and making them like in the original one.
For that, you need to set the function type to WINAPI (actually it is __stdcall but it seems that the compiler/linker somehow differentiates them? Because the mangling behaviour was different between __stdcall and WINAPI) and define the function parameters - you can calculate the number of needed ones from the last part of the mangled name (which is actually not present in the resulting DLL with the DEF file): #4 means one 4 bytes sized parameter (example - int), #8 means two, etc. You don't even need to know which is exactly the parameter type if you are working with wrappit generated functions - you just need to adjust the size to make mangling correct.
Next, you need to define the relation between the mangled names and ordinals in the DEF file.
There is probably a better and easier approach of using #pragma comment(linker, "/EXPORT:Function=Function#4,#1"), as per C++ DLL Export: Decorated/Mangled names (#wqw's answer) but I haven't tried it.
Also I needed to set up the relocations in project settings - that was probably the cause of "ERROR_INVALID_ADDRESS".
Case closed.

path resolution of include

Is there a definitive way to see where a given #include <example.h> resolves to? I have a #include <linux/unistd.h> in my code but I don't know which unistd.h is being used.
If you use the -E command line option to get the preprocessor output, it will tell you the full path to every header file included, including those included by other headers. For example:
$ cat test.c
#include <unistd.h>
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 1 "/usr/include/unistd.h" 1 3 4
# 71 "/usr/include/unistd.h" 3 4
# 1 "/usr/include/_types.h" 1 3 4
# 27 "/usr/include/_types.h" 3 4
# 1 "/usr/include/sys/_types.h" 1 3 4
# 32 "/usr/include/sys/_types.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 33 "/usr/include/sys/_types.h" 2 3 4
# 1 "/usr/include/machine/_types.h" 1 3 4
# 34 "/usr/include/machine/_types.h" 3 4
# 1 "/usr/include/i386/_types.h" 1 3 4
# 37 "/usr/include/i386/_types.h" 3 4
typedef signed char __int8_t;
(lots more output)
So in this case, the header that's being used is /usr/include/unistd.h.
From the GCC documentation,
On a normal Unix system, if you do not
instruct it otherwise, it will look
for headers requested with #include
in:
/usr/local/include
libdir/gcc/target/version/include
/usr/target/include
/usr/include
In the above, target is the canonical
name of the system GCC was configured
to compile code for; often but not
always the same as the canonical name
of the system it runs on. version is
the version of GCC in use.
You can add to this list with the
-Idir command line option. All the directories named by -I are searched,
in left-to-right order, before the
default directories. The only
exception is when dir is already
searched by default. In this case, the
option is ignored and the search order
for system directories remains
unchanged.
So unless you're adding the -I (capital eye, not ell) switch, the version included is the version found in the first of those directories that holds it.

How to set CPU affinity for a process from C or C++ in Linux?

Is there a programmatic method to set CPU affinity for a process in c/c++ for the Linux operating system?
You need to use sched_setaffinity(2).
For example, to run on CPUs 0 and 2 only:
#define _GNU_SOURCE
#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
CPU_SET(2, &mask);
int result = sched_setaffinity(0, sizeof(mask), &mask);
(0 for the first parameter means the current process, supply a PID if it's some other process you want to control).
See also sched_getcpu(3).
Use sched_setaffinity at the process level, or pthread_attr_setaffinity_np for individual threads.
I have done many effort to realize what is happening so I add this answer for helping people like me(I use gcc compiler in linux mint)
#include <sched.h>
cpu_set_t mask;
inline void assignToThisCore(int core_id)
{
CPU_ZERO(&mask);
CPU_SET(core_id, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
}
int main(){
//cal this:
assignToThisCore(2);//assign to core 0,1,2,...
return 0;
}
But don't forget to add this options to the compiler command : -D _GNU_SOURCE
Because operating system might assign a process to the particular core, you can add this GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3" to the grub file located in /etc/default and the run sudo update-grub in terminal to reserve the cores you want
UPDATE:
If you want to assign more cores you can follow this piece of code:
inline void assignToThisCores(int core_id1, int core_id2)
{
CPU_ZERO(&mask1);
CPU_SET(core_id1, &mask1);
CPU_SET(core_id2, &mask1);
sched_setaffinity(0, sizeof(mask1), &mask1);
//__asm__ __volatile__ ( "vzeroupper" : : : ); // It is hear because of that bug which dirtied the AVX registers, so, if you rely on AVX uncomment it.
}
sched_setaffinity + sched_getaffinity minimal C runnable example
This example was extracted from my answer at: How to use sched_getaffinity and sched_setaffinity in Linux from C? I believe the questions are not duplicates since that one is a subset of this one, as it asks about sched_getaffinity only, and does not mention C++.
In this example, we get the affinity, modify it, and check if it has taken effect with sched_getcpu().
main.c
#define _GNU_SOURCE
#include <assert.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void print_affinity() {
cpu_set_t mask;
long nproc, i;
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_getaffinity");
assert(false);
}
nproc = sysconf(_SC_NPROCESSORS_ONLN);
printf("sched_getaffinity = ");
for (i = 0; i < nproc; i++) {
printf("%d ", CPU_ISSET(i, &mask));
}
printf("\n");
}
int main(void) {
cpu_set_t mask;
print_affinity();
printf("sched_getcpu = %d\n", sched_getcpu());
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_setaffinity");
assert(false);
}
print_affinity();
/* TODO is it guaranteed to have taken effect already? Always worked on my tests. */
printf("sched_getcpu = %d\n", sched_getcpu());
return EXIT_SUCCESS;
}
GitHub upstream.
Compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Sample output:
sched_getaffinity = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
sched_getcpu = 9
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
Which means that:
initially, all of my 16 cores were enabled, and the process was randomly running on core 9 (the 10th one)
after we set the affinity to only the first core, the process was moved necessarily to core 0 (the first one)
It is also fun to run this program through taskset:
taskset -c 1,3 ./a.out
Which gives output of form:
sched_getaffinity = 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 2
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
and so we see that it limited the affinity from the start.
This works because the affinity is inherited by child processes, which taskset is forking: How to prevent inheriting CPU affinity by child forked process?
Python: os.sched_getaffinity and os.sched_setaffinity
See: How to find out the number of CPUs using python
Tested in Ubuntu 16.04.
In short
unsigned long mask = 7; /* processors 0, 1, and 2 */
unsigned int len = sizeof(mask);
if (sched_setaffinity(0, len, &mask) < 0) {
perror("sched_setaffinity");
}
Look in CPU Affinity for more details
It is also possible to make it through the shell without any modification in the programs with the cgroups and the cpuset sub-system. Cgroups (v1 at least) are typically mounted on /sys/fs/cgroup under which the cpuset sub-system resides. For example:
$ ls -l /sys/fs/cgroup/
total 0
drwxr-xr-x 15 root root 380 nov. 22 20:00 ./
drwxr-xr-x 8 root root 0 nov. 22 20:00 ../
dr-xr-xr-x 2 root root 0 nov. 22 20:00 blkio/
[...]
lrwxrwxrwx 1 root root 11 nov. 22 20:00 cpuacct -> cpu,cpuacct/
dr-xr-xr-x 2 root root 0 nov. 22 20:00 cpuset/
dr-xr-xr-x 5 root root 0 nov. 22 20:00 devices/
dr-xr-xr-x 3 root root 0 nov. 22 20:00 freezer/
[...]
Under cpuset, the cpuset.cpus defines the range of CPUs on which the processes belonging to this cgroup are allowed to run. Here, at the top level, all the CPUs are configured for all the processes of the system. Here, the system has 8 CPUs:
$ cd /sys/fs/cgroup/cpuset
$ cat cpuset.cpus
0-7
The list of processes belonging to this cgroup is listed in the cgroup.procs file:
$ cat cgroup.procs
1
2
3
[...]
12364
12423
12424
12425
[...]
It is possible to create a child cgroup into which a subset of CPUs are allowed. For example, let's define a sub-cgroup with CPU cores 1 and 3:
$ pwd
/sys/fs/cgroup/cpuset
$ sudo mkdir subset1
$ cd subset1
$ pwd
/sys/fs/cgroup/cpuset/subset1
$ ls -l
total 0
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.clone_children
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.procs
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_migrate
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 nov. 22 23:28 notify_on_release
-rw-r--r-- 1 root root 0 nov. 22 23:28 tasks
$ cat cpuset.cpus
$ sudo sh -c "echo 1,3 > cpuset.cpus"
$ cat cpuset.cpus
1,3
The cpuset.mems files must be filled before moving any process into this cgroup. Here we move the current shell into this new cgroup (we merely write the pid of the process to move into the cgroup.procs file):
$ cat cgroup.procs
$ echo $$
4753
$ sudo sh -c "echo 4753 > cgroup.procs"
sh: 1: echo: echo: I/O error
$ cat cpuset.mems
$ sudo sh -c "echo 0 > cpuset.mems"
$ cat cpuset.mems
0
$ sudo sh -c "echo 4753 > cgroup.procs"
$ cat cgroup.procs
4753
12569
The latter shows that the current shell (pid#4753) is now located in the newly created cgroup (the second pid 12569 is the cat's command one as being the child of the current shell, it inherits its cgroups). With a formatted ps command, it is possible to verify on which CPU the processes are running (PSR column):
$ ps -o pid,ppid,psr,command
PID PPID PSR COMMAND
4753 2372 3 bash
12672 4753 1 ps -o pid,ppid,psr,command
We can see that the current shell is running on CPU#3 and its child (ps command) which inherits the its cgroups is running on CPU#1.
As a conclusion, instead of using sched_setaffinity() or any pthread service, it is possible to create a cpuset hierarchy in the cgroups tree and move the processes into them by writing their pids in the corresponding cgroup.procs files.

Resources