diff --git a/userspace/power_burn/power_burn_max.c b/userspace/power_burn/power_burn_max.c index 7b3a361..5bbd5c4 100644 --- a/userspace/power_burn/power_burn_max.c +++ b/userspace/power_burn/power_burn_max.c @@ -1,12 +1,13 @@ /* - * power_burn_max - CPU/GPU/LED power burn for tici. + * power_burn_max - short CPU/LED-only power blip for boot. * - * power_burn_max [seconds] [n_perf_cores] + * power_burn_max [seconds] [n_cores] + * + * seconds may be fractional. n_cores defaults to all 8 SDM845 cores; use 4 to + * burn only the big cluster. */ #define _GNU_SOURCE -#include -#include #include #include #include @@ -30,205 +31,199 @@ static void stop_sig(int s) { exit_signum = s; running = 0; } #define POWER_TEST_MAGIC 0x57505354u /* "WPST" */ static void write_magic(uint32_t val) { - int fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd < 0) { perror("open /dev/mem"); return; } - const uintptr_t page = POWER_TEST_ADDR & ~0xFFFull; - const uintptr_t off = POWER_TEST_ADDR & 0xFFFull; - void *p = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)page); - if (p == MAP_FAILED) { perror("mmap /dev/mem"); close(fd); return; } - *(volatile uint32_t *)((char *)p + off) = val; - msync(p, 0x1000, MS_SYNC); - munmap(p, 0x1000); - close(fd); + int fd = open("/dev/mem", O_RDWR | O_SYNC); + if (fd < 0) return; + const uintptr_t page = POWER_TEST_ADDR & ~0xFFFull; + const uintptr_t off = POWER_TEST_ADDR & 0xFFFull; + void *p = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)page); + if (p == MAP_FAILED) { close(fd); return; } + *(volatile uint32_t *)((char *)p + off) = val; + msync(p, 0x1000, MS_SYNC); + munmap(p, 0x1000); + close(fd); } -#define MAX_SAVED 96 -static struct { char path[192]; char val[48]; } saved[MAX_SAVED]; +#define MAX_SAVED 128 +static struct { char path[192]; char val[64]; } saved[MAX_SAVED]; static int nsaved; static int sysfs_read(const char *p, char *b, int sz) { - FILE *f = fopen(p, "r"); - if (!f) return -1; - if (!fgets(b, sz, f)) { fclose(f); return -1; } - fclose(f); - b[strcspn(b, "\n")] = 0; - return 0; + FILE *f = fopen(p, "r"); + if (!f) return -1; + if (!fgets(b, sz, f)) { fclose(f); return -1; } + fclose(f); + b[strcspn(b, "\n")] = 0; + return 0; } + static void sysfs_write(const char *p, const char *v) { - FILE *f = fopen(p, "w"); - if (!f) return; - fputs(v, f); - fclose(f); + FILE *f = fopen(p, "w"); + if (!f) return; + fputs(v, f); + fclose(f); } + static void save_and_write(const char *p, const char *v) { - if (nsaved < MAX_SAVED && sysfs_read(p, saved[nsaved].val, sizeof(saved[0].val)) == 0) { - strncpy(saved[nsaved].path, p, sizeof(saved[0].path) - 1); - nsaved++; - } - sysfs_write(p, v); + if (nsaved < MAX_SAVED && sysfs_read(p, saved[nsaved].val, sizeof(saved[0].val)) == 0) { + strncpy(saved[nsaved].path, p, sizeof(saved[0].path) - 1); + saved[nsaved].path[sizeof(saved[0].path) - 1] = 0; + nsaved++; + } + sysfs_write(p, v); } + static void restore_all(void) { - for (int i = nsaved - 1; i >= 0; i--) sysfs_write(saved[i].path, saved[i].val); + for (int i = nsaved - 1; i >= 0; i--) sysfs_write(saved[i].path, saved[i].val); } + static void fatal_sig(int s) { - const char *m = "[power_burn_max] fault: signal\n"; - switch (s) { - case SIGABRT: m = "[power_burn_max] fault: SIGABRT\n"; break; - case SIGSEGV: m = "[power_burn_max] fault: SIGSEGV\n"; break; - case SIGBUS: m = "[power_burn_max] fault: SIGBUS\n"; break; - } - (void)!write(2, m, strlen(m)); - write_magic(0); - restore_all(); - _exit(128 + s); + write_magic(0); + restore_all(); + _exit(128 + s); } static void leds_on(void) { - save_and_write("/sys/class/leds/led:torch_0/brightness", "500"); - save_and_write("/sys/class/leds/led:torch_1/brightness", "500"); - save_and_write("/sys/class/leds/led:torch_2/brightness", "300"); - save_and_write("/sys/class/leds/led:switch_0/brightness", "255"); - save_and_write("/sys/class/leds/led:switch_1/brightness", "255"); - save_and_write("/sys/class/leds/led:switch_2/brightness", "255"); + save_and_write("/sys/class/leds/led:torch_0/brightness", "500"); + save_and_write("/sys/class/leds/led:torch_1/brightness", "500"); + save_and_write("/sys/class/leds/led:torch_2/brightness", "300"); + save_and_write("/sys/class/leds/led:switch_0/brightness", "255"); + save_and_write("/sys/class/leds/led:switch_1/brightness", "255"); + save_and_write("/sys/class/leds/led:switch_2/brightness", "255"); } -static void freq_max(void) { - /* max_pwrlevel=0 unlocks the 710MHz step that Adreno gates off by default - * even under governor=performance. */ - save_and_write("/sys/class/kgsl/kgsl-3d0/devfreq/governor", "performance"); - save_and_write("/sys/class/kgsl/kgsl-3d0/max_pwrlevel", "0"); - save_and_write("/sys/class/kgsl/kgsl-3d0/force_bus_on", "1"); - save_and_write("/sys/class/kgsl/kgsl-3d0/force_clk_on", "1"); - save_and_write("/sys/class/kgsl/kgsl-3d0/force_rail_on", "1"); - save_and_write("/sys/class/kgsl/kgsl-3d0/force_no_nap", "1"); - save_and_write("/sys/class/devfreq/soc:qcom,gpubw/governor", "performance"); - save_and_write("/sys/class/devfreq/soc:qcom,cpubw/governor", "performance"); - save_and_write("/sys/class/devfreq/soc:qcom,llccbw/governor", "performance"); - save_and_write("/sys/class/devfreq/soc:qcom,l3-cpu0/governor","performance"); - save_and_write("/sys/class/devfreq/soc:qcom,l3-cpu4/governor","performance"); - save_and_write("/sys/class/devfreq/soc:qcom,l3-cdsp/governor","performance"); + +static void cpu_bus_freq_max(void) { + save_and_write("/sys/class/devfreq/soc:qcom,cpubw/governor", "performance"); + save_and_write("/sys/class/devfreq/soc:qcom,llccbw/governor", "performance"); + save_and_write("/sys/class/devfreq/soc:qcom,l3-cpu0/governor", "performance"); + save_and_write("/sys/class/devfreq/soc:qcom,l3-cpu4/governor", "performance"); } -static void pin_perf_core(int cpu) { - char path[128]; - snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/online", cpu); - save_and_write(path, "1"); - snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu); - save_and_write(path, "performance"); + +static void pin_core(int cpu) { + char path[160]; + char max_freq[32]; + + snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); + if (sysfs_read(path, max_freq, sizeof(max_freq)) != 0) + max_freq[0] = 0; + + snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/online", cpu); + save_and_write(path, "1"); + + if (max_freq[0]) { + snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + save_and_write(path, max_freq); + snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); + save_and_write(path, max_freq); + } + + snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu); + save_and_write(path, "performance"); } static void *cpu_burn(void *arg) { - int core = (int)(intptr_t)arg; - cpu_set_t set; CPU_ZERO(&set); CPU_SET(core, &set); - pthread_setaffinity_np(pthread_self(), sizeof(set), &set); + int core = (int)(intptr_t)arg; + cpu_set_t set; CPU_ZERO(&set); CPU_SET(core, &set); + pthread_setaffinity_np(pthread_self(), sizeof(set), &set); - /* Contraction map x := 0.5*x + 0.25 — fixed point at 0.5, keeps values - * bounded away from subnormal/NaN paths that short-circuit the FPU. */ - float32x4_t v0 = vdupq_n_f32(0.50f + core * 0.01f); - float32x4_t v1 = vdupq_n_f32(0.25f); - float32x4_t v2 = vdupq_n_f32(0.75f); - float32x4_t v3 = vdupq_n_f32(0.125f); - float32x4_t v4 = vdupq_n_f32(0.875f); - float32x4_t v5 = vdupq_n_f32(0.625f); - float32x4_t v6 = vdupq_n_f32(0.375f); - float32x4_t v7 = vdupq_n_f32(0.1875f); - const float32x4_t half = vdupq_n_f32(0.5f); - const float32x4_t quarter = vdupq_n_f32(0.25f); - - while (running) { - for (int i = 0; i < 10000; i++) { - v0 = vfmaq_f32(quarter, v0, half); - v1 = vfmaq_f32(quarter, v1, half); - v2 = vfmaq_f32(quarter, v2, half); - v3 = vfmaq_f32(quarter, v3, half); - v4 = vfmaq_f32(quarter, v4, half); - v5 = vfmaq_f32(quarter, v5, half); - v6 = vfmaq_f32(quarter, v6, half); - v7 = vfmaq_f32(quarter, v7, half); - } - } - volatile float sink = vgetq_lane_f32(v0,0) + vgetq_lane_f32(v1,0) + vgetq_lane_f32(v2,0) + - vgetq_lane_f32(v3,0) + vgetq_lane_f32(v4,0) + vgetq_lane_f32(v5,0) + - vgetq_lane_f32(v6,0) + vgetq_lane_f32(v7,0); - (void)sink; + void *mem = NULL; + if (posix_memalign(&mem, 64, 4096) != 0) return NULL; + memset(mem, core, 4096); + + const uint32_t a = 0x3f000000u + (uint32_t)core; + const uint32_t b = 0x3e800000u + (uint32_t)core; + const uint32_t c = 0x3f4ccccdu + (uint32_t)core; + + while (running) { + asm volatile( + "dup v0.4s, %w[a]\n" + "dup v1.4s, %w[b]\n" + "dup v2.4s, %w[c]\n" + "dup v3.4s, %w[a]\n" + "dup v4.4s, %w[b]\n" + "dup v5.4s, %w[c]\n" + "dup v6.4s, %w[a]\n" + "dup v7.4s, %w[b]\n" + "dup v16.4s, %w[c]\n" + "dup v17.4s, %w[a]\n" + "dup v18.4s, %w[b]\n" + "dup v19.4s, %w[c]\n" + "mov x9, #10000\n" + "1:\n" + "ldp q20, q21, [%[p], #0]\n" + "fmla v0.4s, v16.4s, v17.4s\n" + "fmla v1.4s, v17.4s, v18.4s\n" + "fmla v2.4s, v18.4s, v19.4s\n" + "fmla v3.4s, v19.4s, v16.4s\n" + "ldp q22, q23, [%[p], #32]\n" + "fmla v4.4s, v16.4s, v18.4s\n" + "fmla v5.4s, v17.4s, v19.4s\n" + "fmla v6.4s, v18.4s, v16.4s\n" + "fmla v7.4s, v19.4s, v17.4s\n" + "eor v20.16b, v20.16b, v22.16b\n" + "fmla v8.4s, v0.4s, v17.4s\n" + "fmla v9.4s, v1.4s, v18.4s\n" + "fmla v10.4s, v2.4s, v19.4s\n" + "fmla v11.4s, v3.4s, v16.4s\n" + "eor v21.16b, v21.16b, v23.16b\n" + "fmla v12.4s, v4.4s, v18.4s\n" + "fmla v13.4s, v5.4s, v19.4s\n" + "fmla v14.4s, v6.4s, v16.4s\n" + "fmla v15.4s, v7.4s, v17.4s\n" + "stp q20, q21, [%[p], #0]\n" + "stp q22, q23, [%[p], #32]\n" + "subs x9, x9, #1\n" + "b.ne 1b\n" + : + : [p] "r" (mem), [a] "r" (a), [b] "r" (b), [c] "r" (c) + : "x9", "cc", "memory", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); + } + + free(mem); + return NULL; } -static const char *GPU_KSRC = - "__kernel void burn(__global float *buf, int n) {" - " int id = get_global_id(0);" - " float4 a = (float4)(0.6f,0.7f,0.8f,0.9f) + (float)(id&15)*0.001f;" - " float4 b=a*0.5f, c=a*0.75f, d=a*0.8f, e=a*0.9f, f=a*0.55f, g=a*0.65f, h=a*0.85f;" - " for (int i = 0; i < n; i++) {" - " a = mad(a,(float4)(0.5f),(float4)(0.25f));" - " b = mad(b,(float4)(0.5f),(float4)(0.25f));" - " c = mad(c,(float4)(0.5f),(float4)(0.25f));" - " d = mad(d,(float4)(0.5f),(float4)(0.25f));" - " e = mad(e,(float4)(0.5f),(float4)(0.25f));" - " f = mad(f,(float4)(0.5f),(float4)(0.25f));" - " g = mad(g,(float4)(0.5f),(float4)(0.25f));" - " h = mad(h,(float4)(0.5f),(float4)(0.25f));" - " }" - " if ((id&1023)==0) buf[id/1024] = a.x+b.x+c.x+d.x+e.x+f.x+g.x+h.x;" - "}"; +static uint64_t mono_ns(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec; +} int main(int argc, char **argv) { - int duration = 1, n_perf = 4; - if (argc > 1) duration = atoi(argv[1]); - if (argc > 2) n_perf = atoi(argv[2]); - if (n_perf < 0) n_perf = 0; if (n_perf > 4) n_perf = 4; + double duration_s = argc > 1 ? strtod(argv[1], NULL) : 1.0; + int n_cores = argc > 2 ? atoi(argv[2]) : 8; + if (n_cores < 0) n_cores = 0; + if (n_cores > 8) n_cores = 8; + int first_cpu = n_cores > 4 ? 0 : 4; - signal(SIGTERM, stop_sig); - signal(SIGINT, stop_sig); - signal(SIGABRT, fatal_sig); - signal(SIGSEGV, fatal_sig); - signal(SIGBUS, fatal_sig); + signal(SIGTERM, stop_sig); + signal(SIGINT, stop_sig); + signal(SIGABRT, fatal_sig); + signal(SIGSEGV, fatal_sig); + signal(SIGBUS, fatal_sig); - freq_max(); - for (int i = 0; i < n_perf; i++) pin_perf_core(4 + i); + cpu_bus_freq_max(); + for (int i = 0; i < n_cores; i++) pin_core(first_cpu + i); + write_magic(POWER_TEST_MAGIC); + leds_on(); - cl_platform_id plat; cl_device_id dev; cl_int err; - clGetPlatformIDs(1, &plat, NULL); - clGetDeviceIDs(plat, CL_DEVICE_TYPE_GPU, 1, &dev, NULL); - cl_context ctx = clCreateContext(NULL, 1, &dev, NULL, NULL, &err); - cl_command_queue q = clCreateCommandQueue(ctx, dev, 0, &err); - cl_program prog = clCreateProgramWithSource(ctx, 1, &GPU_KSRC, NULL, &err); - clBuildProgram(prog, 1, &dev, "-cl-fast-relaxed-math -cl-mad-enable", NULL, NULL); - cl_kernel kern = clCreateKernel(prog, "burn", &err); - cl_mem buf = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY, 4096 * sizeof(float), NULL, &err); - int n_inner = 200; - clSetKernelArg(kern, 0, sizeof(cl_mem), &buf); - clSetKernelArg(kern, 1, sizeof(int), &n_inner); - const size_t gs = 65536; + pthread_t th[8]; + for (int i = 0; i < n_cores; i++) + pthread_create(&th[i], NULL, cpu_burn, (void *)(intptr_t)(first_cpu + i)); - write_magic(POWER_TEST_MAGIC); + uint64_t end_ns = duration_s > 0.0 ? mono_ns() + (uint64_t)(duration_s * 1000000000.0) : 0; + while (running) { + if (end_ns && mono_ns() >= end_ns) break; + usleep(1000); + } + running = 0; - pthread_t cpu_th[4]; - for (int i = 0; i < n_perf; i++) - pthread_create(&cpu_th[i], NULL, cpu_burn, (void *)(intptr_t)(4 + i)); - - leds_on(); - - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t t_end_ns = (uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec + (uint64_t)duration * 1000000000ull; - while (running) { - clEnqueueNDRangeKernel(q, kern, 1, NULL, &gs, NULL, 0, NULL, NULL); - clFinish(q); - if (duration > 0) { - clock_gettime(CLOCK_MONOTONIC, &ts); - if ((uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec >= t_end_ns) break; - } - } - running = 0; - - for (int i = 0; i < n_perf; i++) pthread_join(cpu_th[i], NULL); - - clReleaseMemObject(buf); - clReleaseKernel(kern); - clReleaseProgram(prog); - clReleaseCommandQueue(q); - clReleaseContext(ctx); - restore_all(); - write_magic(0); - if (exit_signum) fprintf(stderr, "[power_burn_max] interrupted by signal %d\n", (int)exit_signum); - return 0; + for (int i = 0; i < n_cores; i++) pthread_join(th[i], NULL); + restore_all(); + write_magic(0); + if (exit_signum) fprintf(stderr, "[power_burn_max] interrupted by signal %d\n", (int)exit_signum); + return 0; } diff --git a/userspace/usr/comma/comma.sh b/userspace/usr/comma/comma.sh index aa1f469..337e0a7 100755 --- a/userspace/usr/comma/comma.sh +++ b/userspace/usr/comma/comma.sh @@ -10,7 +10,7 @@ RESET_TRIGGER="/data/__system_reset__" # blip power to ~10W to see if the PSU is stable if grep -q mici /sys/firmware/devicetree/base/model; then - sudo timeout --kill-after=2 5 /home/comma/power_burn_max + sudo timeout --kill-after=2 5 /home/comma/power_burn_max 0.3 8 fi # use max freq to boot up quickly, then limit