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 {
150150 /// TODO copy elision / named return values so that the threads referencing *Loop
151151 /// have the correct pointer value.
152152 fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
153 // TODO check the actual cpu core count
154 return self.initInternal(allocator, 4);
153 const core_count = try std.os.cpuCount(allocator);
154 return self.initInternal(allocator, core_count);
155155 }
156156
157157 /// 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 {
361361 fn free(allocator: *Allocator, bytes: []u8) void {}
362362};
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
364431test "c_allocator" {
365432 if (builtin.link_libc) {
366433 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 {
27482748
27492749 return stat;
27502750}
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 {
11971197 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
11981198}
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
12001204pub const epoll_data = packed union {
12011205 ptr: usize,
12021206 fd: i32,
std/os/test.zig+5
......@@ -58,3 +58,8 @@ fn start2(ctx: *i32) u8 {
5858 _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
5959 return 0;
6060}
61
62test "cpu count" {
63 const cpu_count = try std.os.cpuCount(a);
64 assert(cpu_count >= 1);
65}