auto_release_temp(); // automatically release temporary memory. print(">%<", S64_MIN + delta, to_standard_error = true); print_to_builder(*builder, "Average % us (% / % bytes) ---------", dbg_average/1000, context.temporary_storage.total_bytes_occupied, context.temporary_storage.high_water_mark); // DEBUG // MEASURE PERFORMANCE { dbg_average := 0; // DEBUG dbg_count := 0; // DEBUG #import "Basic"; // Cumulative average: CA_n+1 = (x_n+1 + n*CA_n ) / (n + 1) start := current_time_monotonic(); // DEBUG // ...code to be measured... stop := current_time_monotonic(); // DEBUG dbg_sample := to_nanoseconds(stop-start); // DEBUG dbg_average = (dbg_sample + dbg_count * dbg_average) / (dbg_count + 1); // DEBUG dbg_count += 1; // DEBUG print("Average % ns.\n", dbg_average); // DEBUG } // Memory allocator debugging. print_owner_allocator :: (tag: string, memory: *void) { owner := "unkown"; if true == xx context.allocator.proc(.IS_THIS_YOURS, 0, 0, memory, null) then owner = "default"; else if true == xx temp.proc(.IS_THIS_YOURS, 0, 0, memory, null) then owner = "temp"; print("'%' belongs to '%'\n", tag, owner); } // ttt's database debugging. print_database :: (db: Database) { for db.tasks { print("% | % : % : % : % : % : % : %\n", cast(string)it.name, it.times[0], it.times[1], it.times[2], it.times[3], it.times[4], it.times[5], it.times[6] ); } } // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- // // Average cumulative calculation. average: float64 = 0; counter: float64 = 0; t0 := current_time_monotonic(); t1 := current_time_monotonic(); set_cursor_position(2, 47); sample := cast(float64)to_nanoseconds(t1-t0)/1000; average = (sample + counter * average) / (counter + 1); counter += 1; print(">%us<", average); // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- // // Implementation of tcsetattr, tcgetattr, and tcflush using only 'ioctl' which is provided by jai. #if USE_LIBC { libc :: #system_library "libc"; // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html tcsetattr :: (fd: s32, optional_actions: s32, termios_p : *Terminal_IO_Mode) -> s32 #foreign libc; // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 #foreign libc; // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcflush.c.html tcflush :: (fd: s32, queue_selector: s32) -> s32 #foreign libc; } else { // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html tcsetattr :: (fd: s32, optional_actions: s32, termios_p : *Terminal_IO_Mode) -> s32 { #if OS == .LINUX { TCSETS :: 0x5402; TCSETSW :: 0x5403; TCSETSF :: 0x5404; tcflag_t :: u32; cc_t :: u8; __KERNEL_NCCS :: 19; __kernel_termios :: struct { c_iflag : tcflag_t; // input mode flags c_oflag : tcflag_t; // output mode flags c_cflag : tcflag_t; // control mode flags c_lflag : tcflag_t; // local mode flags c_line : cc_t; // line discipline c_cc : [__KERNEL_NCCS]cc_t; // control characters }; k_termios: __kernel_termios; cmd: u64; if optional_actions == { case xx Optional_Actions.TCSANOW; cmd = TCSETS; case xx Optional_Actions.TCSADRAIN; cmd = TCSETSW; case xx Optional_Actions.TCSAFLUSH; cmd = TCSETSF; case; return EINVAL; } // k_termios.c_iflag = termios_p.c_iflag & ~IBAUD0; k_termios.c_iflag = xx termios_p.c_iflag; k_termios.c_oflag = xx termios_p.c_oflag; k_termios.c_cflag = xx termios_p.c_cflag; k_termios.c_lflag = xx termios_p.c_lflag; k_termios.c_line = xx termios_p.c_line; // #if _HAVE_C_ISPEED && _HAVE_STRUCT_TERMIOS_C_ISPEED // k_termios.c_ispeed = termios_p->c_ispeed; // #endif // #if _HAVE_C_OSPEED && _HAVE_STRUCT_TERMIOS_C_OSPEED // k_termios.c_ospeed = termios_p->c_ospeed; // #endif memcpy(*k_termios.c_cc[0], *termios_p.c_cc[0], __KERNEL_NCCS * 1);//size_of(cc_t)); return ioctl(fd, cmd, *k_termios); } #if OS == .MACOS { // return __ioctl (fd, TIOCSETAF, termios_p); #assert(false, "NOT IMPLEMENTED"); } return 0; } // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 { TCSETS :: 0x5402; TCSETSW :: 0x5403; TCSETSF :: 0x5404; tcflag_t :: u32; cc_t :: u8; __KERNEL_NCCS :: 19; __kernel_termios :: struct { c_iflag : tcflag_t; // input mode flags c_oflag : tcflag_t; // output mode flags c_cflag : tcflag_t; // control mode flags c_lflag : tcflag_t; // local mode flags c_line : cc_t; // line discipline c_cc : [__KERNEL_NCCS]cc_t; // control characters }; // int // __tcgetattr (int fd, struct termios *termios_p) // { // struct __kernel_termios k_termios; k_termios: __kernel_termios; retval: int; retval = ioctl(fd, TCGETS, *k_termios); if retval == 0 { termios_p.c_iflag = xx k_termios.c_iflag; termios_p.c_oflag = xx k_termios.c_oflag; termios_p.c_cflag = xx k_termios.c_cflag; termios_p.c_lflag = xx k_termios.c_lflag; termios_p.c_line = xx k_termios.c_line; // #if _HAVE_STRUCT_TERMIOS_C_ISPEED // # if _HAVE_C_ISPEED // termios_p->c_ispeed = k_termios.c_ispeed; // # else // termios_p->c_ispeed = k_termios.c_cflag & (CBAUD | CBAUDEX); // # endif // #endif // #if _HAVE_STRUCT_TERMIOS_C_OSPEED // # if _HAVE_C_OSPEED // termios_p->c_ospeed = k_termios.c_ospeed; // # else // termios_p->c_ospeed = k_termios.c_cflag & (CBAUD | CBAUDEX); // # endif // #endif size_of_cc_t := __KERNEL_NCCS * 1; memcpy(*termios_p.c_cc[0], *k_termios.c_cc[0], size_of_cc_t); // memset(*termios_p.c_cc[0] + size_of_cc_t + 1, _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * 1); // // if (sizeof (cc_t) == 1 || _POSIX_VDISABLE == 0 || (unsigned char) _POSIX_VDISABLE == (unsigned char) -1) { // memset (__mempcpy (&termios_p->c_cc[0], &k_termios.c_cc[0], __KERNEL_NCCS * sizeof (cc_t)), _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * sizeof (cc_t)); // } // else // { // memcpy (&termios_p->c_cc[0], &k_termios.c_cc[0], __KERNEL_NCCS * sizeof (cc_t)); // for (size_t cnt = __KERNEL_NCCS; cnt < NCCS; ++cnt) { // termios_p->c_cc[cnt] = _POSIX_VDISABLE; // } // } } return xx retval; } // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcflush.c.html tcflush :: inline (fd: s32, queue_selector: s32) -> s32 { TCFLSH :: 0x540B; return ioctl(fd, TCFLSH, queue_selector); } } // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- // Step_Iterator :: struct { min: int; max: int; step: int; } step_iterator :: (min: int, max: int, step: int) -> Step_Iterator { return .{ min, max, step }; } for_expansion :: (iterator: Step_Iterator, body: Code, flags: For_Flags) #expand { iteration_count: int; for <=cast(bool)(flags & .REVERSE) i: iterator.min..iterator.max { iteration_count += 1; if iteration_count % iterator.step == 0 continue; `it := i; `it_index := void; #insert body; } } for step_iterator(0, 10, 2) { log("%", it); } // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- // // Check what's going on with the temp allocator: // Is it really the responsible for these paths? // It seems that the next beta (after 0.1.055b) compiler allows us to check this pretty easily. // // // An example that uses several different allocators, then asks them all // who owns which memory. // // Note that this is probably not the kind of thing you want to do at runtime // in the steady state, as it may not be very fast, but it could be a very helpful // debugging facility. // #import "Basic"; #import "Pool"; #import "Flat_Pool"; #import "rpmalloc"; main :: () { pool: Pool; flat: Flat_Pool; a := context.default_allocator; b := Allocator.{pool_allocator_proc, *pool}; c := Allocator.{flat_pool_allocator_proc, *flat}; d := Allocator.{rpmalloc_allocator_proc, null}; d.proc(.STARTUP, 0, 0, null, null); // rpmalloc needs explicit init right now, but others don't. ma := alloc(1000, allocator=a); mb := alloc(1000, allocator=b); mc := alloc(1000, allocator=c); md := alloc(1000, allocator=d); report_who_owns(ma, a, b, c, d); report_who_owns(mb, a, b, c, d); report_who_owns(mc, a, b, c, d); report_who_owns(md, a, b, c, d); } report_who_owns :: (memory: *void, allocators: .. Allocator) { someone_owns_this := false; print("Querying all allocators for address: %\n", memory); for allocators { caps, name := get_capabilities(it); assert((caps & .IS_THIS_YOURS) != 0); // It had better be claiming to support this! yours := cast(bool) it.proc(.IS_THIS_YOURS, 0, 0, memory, it.data); print("[%] says \"%\"\n", yours, name); someone_owns_this ||= yours; } assert(someone_owns_this); } // --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- // checked_add :: (a: $T, b: T) -> result: T, overflow: bool #modify { if T.type == .INTEGER return; T = null; } { overflow: bool; result: T = a + b; info := type_info(T); if info.signed { // (+A) + (+B) = −C // (−A) + (−B) = +C if ((a > 0) && (b > 0) && (result < 0)) || ((a < 0) && (b < 0) && (result > 0)) { overflow = true; } } else { if result < a { overflow = true; } } return result, overflow; } checked_sub :: (a: $T, b: T) -> result: T, overflow: bool #modify { if T.type == .INTEGER return; T = null; } { overflow: bool; result: T = a - b; info := type_info(T); if info.signed { // (+A) − (−B) = −C // (−A) − (+B) = +C if ((a > 0) && (b < 0) && (result < 0)) || ((a < 0) && (b > 0) && (result > 0)) { overflow = true; } } else { if result > a { overflow = true; } } return result, overflow; }