@@ -531,6 +531,8 @@ namespace Cpu {
531531 vector<Draw::Graph> graphs_upper;
532532 vector<Draw::Graph> graphs_lower;
533533 Draw::Meter cpu_meter;
534+ #ifdef __APPLE__
535+ #endif
534536 vector<Draw::Meter> gpu_meters;
535537 vector<Draw::Graph> core_graphs;
536538 vector<Draw::Graph> temp_graphs;
@@ -698,7 +700,6 @@ namespace Cpu {
698700 }
699701
700702 cpu_meter = Draw::Meter{cpu_meter_width, " cpu" };
701-
702703 if (mid_line) {
703704 out += Mv::to (y + graph_up_height + 1 , x) + Fx::ub + Theme::c (" cpu_box" ) + Symbols::div_left + Theme::c (" div_line" )
704705 + Symbols::h_line * (width - b_width - 2 ) + Symbols::div_right
@@ -834,6 +835,12 @@ namespace Cpu {
834835 + Symbols::h_line * ((freq_range ? 17 : 7 ) - cpuHz.size ())
835836 + Symbols::title_left + Fx::b + Theme::c (" title" ) + cpuHz + Fx::ub + Theme::c (" div_line" ) + Symbols::title_right;
836837
838+ #ifdef __APPLE__
839+ // ? Skip default CPU bar if we have P/E cores - we'll draw P-CPU and E-CPU bars in the core section
840+ const bool skip_cpu_bar = (Cpu::cpu_core_info.p_cores > 0 and Cpu::cpu_core_info.e_cores > 0 );
841+ if (not skip_cpu_bar)
842+ #endif
843+ {
837844 out += Mv::to (b_y + 1 , b_x + 1 ) + Theme::c (" main_fg" ) + Fx::b + " CPU " + cpu_meter (safeVal (cpu.cpu_percent , " total" s).back ())
838845 + Theme::g (" cpu" ).at (clamp (safeVal (cpu.cpu_percent , " total" s).back (), 0ll , 100ll )) + rjust (to_string (safeVal (cpu.cpu_percent , " total" s).back ()), 4 ) + Theme::c (" main_fg" ) + ' %' ;
839846 if (show_temps) {
@@ -850,10 +857,11 @@ namespace Cpu {
850857 string cwatts_post = " W" ;
851858
852859 max_observed_pwr = max (max_observed_pwr, cpu.usage_watts );
853- out += Theme::g (" cached" ).at (clamp (cpu.usage_watts / max_observed_pwr * 100 .0f , 0 .0f , 100 .0f )) + cwatts + Theme::c (" main_fg" ) + cwatts_post;
860+ out += Theme::g (" cached" ).at (clamp (cpu.usage_watts / max_observed_pwr * 100 .0f , 0 .0f , 100 .0f )) + cwatts + Theme::c (" main_fg" ) + cwatts_post;
854861 }
855862
856863 out += Theme::c (" div_line" ) + Symbols::v_line;
864+ }
857865 } catch (const std::exception& e) {
858866 throw std::runtime_error (" graphs, clock, meter : " + string{e.what ()});
859867 }
@@ -870,12 +878,41 @@ namespace Cpu {
870878 };
871879
872880 // ? Core text and graphs
881+ #ifdef __APPLE__
882+ // ? On Apple Silicon, start at row 0 since we skip the default CPU bar
883+ const bool pe_layout = (Cpu::cpu_core_info.p_cores > 0 and Cpu::cpu_core_info.e_cores > 0 );
884+ int cx = 0 , cy = (pe_layout ? 0 : 1 ), cc = 0 , core_width = (b_column_size == 0 ? 2 : 3 );
885+ #else
873886 int cx = 0 , cy = 1 , cc = 0 , core_width = (b_column_size == 0 ? 2 : 3 );
887+ #endif
874888 if (Shared::coreCount >= 100 ) core_width++;
875- for (const auto & n : iota (0 , Shared::coreCount)) {
889+
890+ // ? Helper lambda to draw a single core line
891+ #ifdef __APPLE__
892+ const int p_cores_count = Cpu::cpu_core_info.p_cores ;
893+ const int e_cores_count = Cpu::cpu_core_info.e_cores ;
894+ const bool use_pe_labels = (p_cores_count > 0 and e_cores_count > 0 );
895+ #endif
896+
897+ auto draw_core = [&](int n) {
876898 auto enabled = is_cpu_enabled (n);
899+ #ifdef __APPLE__
900+ string core_label;
901+ if (use_pe_labels) {
902+ // On Apple Silicon: E-cores are indices 0 to e_cores-1, P-cores are e_cores to end
903+ if (n < e_cores_count) {
904+ core_label = " E" + to_string (n);
905+ } else {
906+ core_label = " P" + to_string (n - e_cores_count);
907+ }
908+ } else {
909+ core_label = (Shared::coreCount < 100 ? " C" : " " ) + to_string (n);
910+ }
911+ out += Mv::to (b_y + cy + 1 , b_x + cx + 1 ) + Theme::c (enabled ? " main_fg" : " inactive_fg" ) + Fx::b + ljust (core_label, core_width + 1 ) + Fx::ub;
912+ #else
877913 out += Mv::to (b_y + cy + 1 , b_x + cx + 1 ) + Theme::c (enabled ? " main_fg" : " inactive_fg" ) + (Shared::coreCount < 100 ? Fx::b + ' C' + Fx::ub : " " )
878914 + ljust (to_string (n), core_width);
915+ #endif
879916 if ((b_column_size > 0 or extra_width > 0 ) and cmp_less (n, core_graphs.size ()))
880917 out += Theme::c (" inactive_fg" ) + graph_bg * (5 * b_column_size + extra_width) + Mv::l (5 * b_column_size + extra_width)
881918 + core_graphs.at (n)(safeVal (cpu.core_percent , n), data_same or redraw);
@@ -893,10 +930,93 @@ namespace Cpu {
893930 }
894931
895932 out += Theme::c (" div_line" ) + Symbols::v_line;
933+ };
896934
897- if ((++cy > ceil ((double )Shared::coreCount / b_columns) or cy == max_row) and n != Shared::coreCount - 1 ) {
898- if (++cc >= b_columns) break ;
899- cy = 1 ; cx = (b_width / b_columns) * cc;
935+ #ifdef __APPLE__
936+ // ? Apple Silicon: Show P-CPU section, then E-CPU section
937+ const int p_cores_total = Cpu::cpu_core_info.p_cores ;
938+ const int e_cores_total = Cpu::cpu_core_info.e_cores ;
939+ const bool has_pe_cores = (p_cores_total > 0 and e_cores_total > 0 );
940+
941+ if (has_pe_cores) {
942+ const int col_width = b_width / b_columns;
943+
944+ // ? On Apple Silicon: E-cores are indices 0 to e_cores-1, P-cores are e_cores to end
945+ // ? Calculate P-core and E-core average percentages
946+ long long p_sum = 0 , e_sum = 0 ;
947+ for (int i = 0 ; i < e_cores_total and i < (int )cpu.core_percent .size (); ++i) {
948+ e_sum += safeVal (cpu.core_percent , i).back ();
949+ }
950+ for (int i = e_cores_total; i < e_cores_total + p_cores_total and i < (int )cpu.core_percent .size (); ++i) {
951+ p_sum += safeVal (cpu.core_percent , i).back ();
952+ }
953+ const long long p_avg = p_cores_total > 0 ? p_sum / p_cores_total : 0 ;
954+ const long long e_avg = e_cores_total > 0 ? e_sum / e_cores_total : 0 ;
955+
956+ // ? P-CPU bar (spans full width of all columns)
957+ string p_label = " P-CPU" ;
958+ const int p_freq = Cpu::cpu_core_info.p_freq_mhz ;
959+ const string p_freq_str = p_freq > 0 ? " " + format_freq (p_freq) : " " ;
960+ // ? Total row width = b_width - 1 (content area, box border is separate)
961+ // ? Content = "P-CPU " (6) + meter + freq_str + border (1) = b_width - 1
962+ const int p_freq_width = static_cast <int >(p_freq_str.size ());
963+ const int p_meter = max (1 , b_width - 7 - p_freq_width - 1 );
964+ out += Mv::to (b_y + cy + 1 , b_x + 1 ) + Theme::c (" main_fg" ) + Fx::b + p_label + Fx::ub + " "
965+ + Draw::Meter{p_meter, " cpu" }(p_avg)
966+ + Theme::g (" cpu" ).at (clamp (p_avg, 0ll , 100ll )) + p_freq_str
967+ + Theme::c (" div_line" ) + Symbols::v_line;
968+ cy++;
969+
970+ // ? Draw P-cores (indices e_cores_total to e_cores_total+p_cores_total-1)
971+ int p_drawn = 0 ;
972+ const int p_rows = (p_cores_total + b_columns - 1 ) / b_columns;
973+ for (int row = 0 ; row < p_rows and p_drawn < p_cores_total and cy < max_row; ++row) {
974+ for (int col = 0 ; col < b_columns and p_drawn < p_cores_total; ++col) {
975+ cx = col * col_width;
976+ draw_core (e_cores_total + p_drawn);
977+ p_drawn++;
978+ }
979+ cy++;
980+ }
981+
982+ // ? E-CPU section header bar (spans full width of all columns)
983+ if (cy < max_row) {
984+ cx = 0 ;
985+ string e_label = " E-CPU" ;
986+ const int e_freq = Cpu::cpu_core_info.e_freq_mhz ;
987+ const string e_freq_str = e_freq > 0 ? " " + format_freq (e_freq) : " " ;
988+ const int e_freq_width = static_cast <int >(e_freq_str.size ());
989+ const int e_meter = max (1 , b_width - 7 - e_freq_width - 1 );
990+ out += Mv::to (b_y + cy + 1 , b_x + 1 ) + Theme::c (" main_fg" ) + Fx::b + e_label + Fx::ub + " "
991+ + Draw::Meter{e_meter, " cpu" }(e_avg)
992+ + Theme::g (" cpu" ).at (clamp (e_avg, 0ll , 100ll )) + e_freq_str
993+ + Theme::c (" div_line" ) + Symbols::v_line;
994+ cy++;
995+ }
996+
997+ // ? Draw E-cores (indices 0 to e_cores_total-1)
998+ const int e_rows = (e_cores_total + b_columns - 1 ) / b_columns;
999+ int e_drawn = 0 ;
1000+ for (int row = 0 ; row < e_rows and e_drawn < e_cores_total and cy < max_row; ++row) {
1001+ for (int col = 0 ; col < b_columns and e_drawn < e_cores_total; ++col) {
1002+ cx = col * col_width;
1003+ draw_core (e_drawn);
1004+ e_drawn++;
1005+ }
1006+ cy++;
1007+ }
1008+ cx = 0 ;
1009+ } else
1010+ #endif
1011+ {
1012+ // ? Standard layout: all cores in columns
1013+ for (const auto & n : iota (0 , Shared::coreCount)) {
1014+ draw_core (n);
1015+
1016+ if ((++cy > ceil ((double )Shared::coreCount / b_columns) or cy == max_row) and n != Shared::coreCount - 1 ) {
1017+ if (++cc >= b_columns) break ;
1018+ cy = 1 ; cx = (b_width / b_columns) * cc;
1019+ }
9001020 }
9011021 }
9021022
@@ -2277,6 +2397,23 @@ namespace Draw {
22772397 b_columns = max (2 , (int )ceil ((double )(Shared::coreCount + 1 ) / (height - gpus_extra_height - 5 )));
22782398 #else
22792399 b_columns = max (1 , (int )ceil ((double )(Shared::coreCount + 1 ) / (height - 5 )));
2400+ #endif
2401+ #ifdef __APPLE__
2402+ // ? On Apple Silicon with P/E cores, we need more rows due to separate sections
2403+ // ? Recalculate b_columns to ensure both P and E sections fit
2404+ if (Cpu::cpu_core_info.p_cores > 0 and Cpu::cpu_core_info.e_cores > 0 ) {
2405+ const int p_cores = Cpu::cpu_core_info.p_cores ;
2406+ const int e_cores = Cpu::cpu_core_info.e_cores ;
2407+ const int available_rows = height - 5 - 2 ; // -2 for P-CPU and E-CPU header bars
2408+ // ? Find minimum columns needed so both P and E sections fit
2409+ // ? Need: ceil(p/cols) + ceil(e/cols) <= available_rows
2410+ while (b_columns < Shared::coreCount) {
2411+ int p_rows = (p_cores + b_columns - 1 ) / b_columns;
2412+ int e_rows = (e_cores + b_columns - 1 ) / b_columns;
2413+ if (p_rows + e_rows <= available_rows) break ;
2414+ b_columns++;
2415+ }
2416+ }
22802417 #endif
22812418 if (b_columns * (21 + 12 * show_temp) < width - (width / 3 )) {
22822419 b_column_size = 2 ;
@@ -2301,6 +2438,22 @@ namespace Draw {
23012438 #else
23022439 b_height = min (height - 2 , (int )ceil ((double )Shared::coreCount / b_columns) + 4 );
23032440 #endif
2441+ #ifdef __APPLE__
2442+ // ? On Apple Silicon with P/E cores, recalculate b_height based on actual P/E row needs
2443+ // ? P/E layout needs: P-CPU header + P rows + E-CPU header + E rows + base (4)
2444+ if (Cpu::cpu_core_info.p_cores > 0 and Cpu::cpu_core_info.e_cores > 0 ) {
2445+ const int p_cores = Cpu::cpu_core_info.p_cores ;
2446+ const int e_cores = Cpu::cpu_core_info.e_cores ;
2447+ int p_rows = (p_cores + b_columns - 1 ) / b_columns;
2448+ int e_rows = (e_cores + b_columns - 1 ) / b_columns;
2449+ // ? +4 base, +2 for P-CPU and E-CPU headers (we skip default CPU bar, so net +1 from original)
2450+ int pe_height = p_rows + e_rows + 4 + 1 ;
2451+ #ifdef GPU_SUPPORT
2452+ pe_height += gpus_extra_height;
2453+ #endif
2454+ b_height = min (height - 2 , pe_height);
2455+ }
2456+ #endif
23042457
23052458 b_x = x + width - b_width - 1 ;
23062459 b_y = y + ceil ((double )(height - 2 ) / 2 ) - ceil ((double )b_height / 2 ) + 1 ;
0 commit comments