authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-07 01:23:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-07 01:23:18-04:00
logc15a6fa9d0e11398f65e8ecc1903e07f4c57add6
tree556306ecdb10cf6841b488e6950e49d2db92005c
parent57f36c420124b3b65d3036f10c4e8c675be29cf4

add std.os.cpuCount and have std.event.Loop use it for thread pool size


5 files changed, 117 insertions(+), 2 deletions(-)

std/event.zig+2-2
...@@ -150,8 +150,8 @@ pub const Loop = struct {...@@ -150,8 +150,8 @@ pub const Loop = struct {
150 /// TODO copy elision / named return values so that the threads referencing *Loop150 /// TODO copy elision / named return values so that the threads referencing *Loop
151 /// have the correct pointer value.151 /// have the correct pointer value.
152 fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {152 fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
153 // TODO check the actual cpu core count153 const core_count = try std.os.cpuCount(allocator);
154 return self.initInternal(allocator, 4);154 return self.initInternal(allocator, core_count);
155 }155 }
156156
157 /// Thread count is the total thread count. The thread pool size will be157 /// Thread count is the total thread count. The thread pool size will be
std/heap.zig+67
...@@ -361,6 +361,73 @@ pub const ThreadSafeFixedBufferAllocator = struct {...@@ -361,6 +361,73 @@ pub const ThreadSafeFixedBufferAllocator = struct {
361 fn free(allocator: *Allocator, bytes: []u8) void {}361 fn free(allocator: *Allocator, bytes: []u8) void {}
362};362};
363363
364pub fn stackFallback(comptime size: usize, fallback_allocator: *Allocator) StackFallbackAllocator(size) {
365 return StackFallbackAllocator(size){
366 .buffer = undefined,
367 .fallback_allocator = fallback_allocator,
368 .fixed_buffer_allocator = undefined,
369 .allocator = Allocator{
370 .allocFn = StackFallbackAllocator(size).alloc,
371 .reallocFn = StackFallbackAllocator(size).realloc,
372 .freeFn = StackFallbackAllocator(size).free,
373 },
374 };
375}
376
377pub fn StackFallbackAllocator(comptime size: usize) type {
378 return struct {
379 const Self = this;
380
381 buffer: [size]u8,
382 allocator: Allocator,
383 fallback_allocator: *Allocator,
384 fixed_buffer_allocator: FixedBufferAllocator,
385
386 pub fn get(self: *Self) *Allocator {
387 self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);
388 return &self.allocator;
389 }
390
391 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
392 const self = @fieldParentPtr(Self, "allocator", allocator);
393 return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator.allocator, n, alignment) catch
394 self.fallback_allocator.allocFn(self.fallback_allocator, n, alignment);
395 }
396
397 fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
398 const self = @fieldParentPtr(Self, "allocator", allocator);
399 const in_buffer = @ptrToInt(old_mem.ptr) >= @ptrToInt(&self.buffer) and
400 @ptrToInt(old_mem.ptr) < @ptrToInt(&self.buffer) + self.buffer.len;
401 if (in_buffer) {
402 return FixedBufferAllocator.realloc(
403 &self.fixed_buffer_allocator.allocator,
404 old_mem,
405 new_size,
406 alignment,
407 ) catch {
408 const result = try self.fallback_allocator.allocFn(
409 self.fallback_allocator,
410 new_size,
411 alignment,
412 );
413 mem.copy(u8, result, old_mem);
414 return result;
415 };
416 }
417 return self.fallback_allocator.reallocFn(self.fallback_allocator, old_mem, new_size, alignment);
418 }
419
420 fn free(allocator: *Allocator, bytes: []u8) void {
421 const self = @fieldParentPtr(Self, "allocator", allocator);
422 const in_buffer = @ptrToInt(bytes.ptr) >= @ptrToInt(&self.buffer) and
423 @ptrToInt(bytes.ptr) < @ptrToInt(&self.buffer) + self.buffer.len;
424 if (!in_buffer) {
425 return self.fallback_allocator.freeFn(self.fallback_allocator, bytes);
426 }
427 }
428 };
429}
430
364test "c_allocator" {431test "c_allocator" {
365 if (builtin.link_libc) {432 if (builtin.link_libc) {
366 var slice = c_allocator.alloc(u8, 50) catch return;433 var slice = c_allocator.alloc(u8, 50) catch return;
std/os/index.zig+39
...@@ -2748,3 +2748,42 @@ pub fn posixFStat(fd: i32) !posix.Stat {...@@ -2748,3 +2748,42 @@ pub fn posixFStat(fd: i32) !posix.Stat {
27482748
2749 return stat;2749 return stat;
2750}2750}
2751
2752pub const CpuCountError = error{
2753 OutOfMemory,
2754 PermissionDenied,
2755 Unexpected,
2756};
2757
2758pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
2759 const usize_count = 16;
2760 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
2761
2762 var set = try allocator.alloc(usize, usize_count);
2763 defer allocator.free(set);
2764
2765 while (true) {
2766 const rc = posix.sched_getaffinity(0, set);
2767 const err = posix.getErrno(rc);
2768 switch (err) {
2769 0 => {
2770 if (rc < set.len * @sizeOf(usize)) {
2771 const result = set[0 .. rc / @sizeOf(usize)];
2772 var sum: usize = 0;
2773 for (result) |x| {
2774 sum += @popCount(x);
2775 }
2776 return sum;
2777 } else {
2778 set = try allocator.realloc(usize, set, set.len * 2);
2779 continue;
2780 }
2781 },
2782 posix.EFAULT => unreachable,
2783 posix.EINVAL => unreachable,
2784 posix.EPERM => return CpuCountError.PermissionDenied,
2785 posix.ESRCH => unreachable,
2786 else => return os.unexpectedErrorPosix(err),
2787 }
2788 }
2789}
std/os/linux/index.zig+4
...@@ -1197,6 +1197,10 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {...@@ -1197,6 +1197,10 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
1197 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));1197 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1198}1198}
11991199
1200pub fn sched_getaffinity(pid: i32, set: []usize) usize {
1201 return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
1202}
1203
1200pub const epoll_data = packed union {1204pub const epoll_data = packed union {
1201 ptr: usize,1205 ptr: usize,
1202 fd: i32,1206 fd: i32,
std/os/test.zig+5
...@@ -58,3 +58,8 @@ fn start2(ctx: *i32) u8 {...@@ -58,3 +58,8 @@ fn start2(ctx: *i32) u8 {
58 _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);58 _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
59 return 0;59 return 0;
60}60}
61
62test "cpu count" {
63 const cpu_count = try std.os.cpuCount(a);
64 assert(cpu_count >= 1);
65}