Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86,fs/resctrl: Support binary fixed point event counters

resctrl assumes that all monitor events can be displayed as unsigned decimal
integers.

Hardware architecture counters may provide some telemetry events with greater
precision where the event is not a simple count, but is a measurement of some
sort (e.g. Joules for energy consumed).

Add a new argument to resctrl_enable_mon_event() for architecture code to
inform the file system that the value for a counter is a fixed-point value
with a specific number of binary places.

Only allow architecture to use floating point format on events that the file
system has marked with mon_evt::is_floating_point which reflects the contract
with user space on how the event values are displayed.

Display fixed point values with values rounded to ceil(binary_bits * log10(2))
decimal places. Special case for zero binary bits to print "{value}.0".

Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Link: https://lore.kernel.org/20251217172121.12030-1-tony.luck@intel.com

authored by

Tony Luck and committed by
Borislav Petkov (AMD)
e37c9a3d ab0308ae

+95 -6
+3 -3
arch/x86/kernel/cpu/resctrl/core.c
··· 902 902 bool ret = false; 903 903 904 904 if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC)) { 905 - resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false); 905 + resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID, false, 0); 906 906 ret = true; 907 907 } 908 908 if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) { 909 - resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID, false); 909 + resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID, false, 0); 910 910 ret = true; 911 911 } 912 912 if (rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL)) { 913 - resctrl_enable_mon_event(QOS_L3_MBM_LOCAL_EVENT_ID, false); 913 + resctrl_enable_mon_event(QOS_L3_MBM_LOCAL_EVENT_ID, false, 0); 914 914 ret = true; 915 915 } 916 916 if (rdt_cpu_has(X86_FEATURE_ABMC))
+74
fs/resctrl/ctrlmondata.c
··· 17 17 18 18 #include <linux/cpu.h> 19 19 #include <linux/kernfs.h> 20 + #include <linux/math.h> 20 21 #include <linux/seq_file.h> 21 22 #include <linux/slab.h> 22 23 #include <linux/tick.h> ··· 602 601 resctrl_arch_mon_ctx_free(r, evt->evtid, rr->arch_mon_ctx); 603 602 } 604 603 604 + /* 605 + * Decimal place precision to use for each number of fixed-point 606 + * binary bits computed from ceil(binary_bits * log10(2)) except 607 + * binary_bits == 0 which will print "value.0" 608 + */ 609 + static const unsigned int decplaces[MAX_BINARY_BITS + 1] = { 610 + [0] = 1, 611 + [1] = 1, 612 + [2] = 1, 613 + [3] = 1, 614 + [4] = 2, 615 + [5] = 2, 616 + [6] = 2, 617 + [7] = 3, 618 + [8] = 3, 619 + [9] = 3, 620 + [10] = 4, 621 + [11] = 4, 622 + [12] = 4, 623 + [13] = 4, 624 + [14] = 5, 625 + [15] = 5, 626 + [16] = 5, 627 + [17] = 6, 628 + [18] = 6, 629 + [19] = 6, 630 + [20] = 7, 631 + [21] = 7, 632 + [22] = 7, 633 + [23] = 7, 634 + [24] = 8, 635 + [25] = 8, 636 + [26] = 8, 637 + [27] = 9 638 + }; 639 + 640 + static void print_event_value(struct seq_file *m, unsigned int binary_bits, u64 val) 641 + { 642 + unsigned long long frac = 0; 643 + 644 + if (binary_bits) { 645 + /* Mask off the integer part of the fixed-point value. */ 646 + frac = val & GENMASK_ULL(binary_bits - 1, 0); 647 + 648 + /* 649 + * Multiply by 10^{desired decimal places}. The integer part of 650 + * the fixed point value is now almost what is needed. 651 + */ 652 + frac *= int_pow(10ull, decplaces[binary_bits]); 653 + 654 + /* 655 + * Round to nearest by adding a value that would be a "1" in the 656 + * binary_bits + 1 place. Integer part of fixed point value is 657 + * now the needed value. 658 + */ 659 + frac += 1ull << (binary_bits - 1); 660 + 661 + /* 662 + * Extract the integer part of the value. This is the decimal 663 + * representation of the original fixed-point fractional value. 664 + */ 665 + frac >>= binary_bits; 666 + } 667 + 668 + /* 669 + * "frac" is now in the range [0 .. 10^decplaces). I.e. string 670 + * representation will fit into chosen number of decimal places. 671 + */ 672 + seq_printf(m, "%llu.%0*llu\n", val >> binary_bits, decplaces[binary_bits], frac); 673 + } 674 + 605 675 int rdtgroup_mondata_show(struct seq_file *m, void *arg) 606 676 { 607 677 struct kernfs_open_file *of = m->private; ··· 750 678 seq_puts(m, "Unavailable\n"); 751 679 else if (rr.err == -ENOENT) 752 680 seq_puts(m, "Unassigned\n"); 681 + else if (evt->is_floating_point) 682 + print_event_value(m, evt->binary_bits, rr.val); 753 683 else 754 684 seq_printf(m, "%llu\n", rr.val); 755 685
+8
fs/resctrl/internal.h
··· 62 62 * Only valid if @evtid is an MBM event. 63 63 * @configurable: true if the event is configurable 64 64 * @any_cpu: true if the event can be read from any CPU 65 + * @is_floating_point: event values are displayed in floating point format 66 + * @binary_bits: number of fixed-point binary bits from architecture, 67 + * only valid if @is_floating_point is true 65 68 * @enabled: true if the event is enabled 66 69 */ 67 70 struct mon_evt { ··· 74 71 u32 evt_cfg; 75 72 bool configurable; 76 73 bool any_cpu; 74 + bool is_floating_point; 75 + unsigned int binary_bits; 77 76 bool enabled; 78 77 }; 79 78 ··· 83 78 84 79 #define for_each_mon_event(mevt) for (mevt = &mon_event_all[QOS_FIRST_EVENT]; \ 85 80 mevt < &mon_event_all[QOS_NUM_EVENTS]; mevt++) 81 + 82 + /* Limit for mon_evt::binary_bits */ 83 + #define MAX_BINARY_BITS 27 86 84 87 85 /** 88 86 * struct mon_data - Monitoring details for each event file.
+8 -2
fs/resctrl/monitor.c
··· 988 988 }, 989 989 }; 990 990 991 - void resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu) 991 + void resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu, unsigned int binary_bits) 992 992 { 993 - if (WARN_ON_ONCE(eventid < QOS_FIRST_EVENT || eventid >= QOS_NUM_EVENTS)) 993 + if (WARN_ON_ONCE(eventid < QOS_FIRST_EVENT || eventid >= QOS_NUM_EVENTS || 994 + binary_bits > MAX_BINARY_BITS)) 994 995 return; 995 996 if (mon_event_all[eventid].enabled) { 996 997 pr_warn("Duplicate enable for event %d\n", eventid); 997 998 return; 998 999 } 1000 + if (binary_bits && !mon_event_all[eventid].is_floating_point) { 1001 + pr_warn("Event %d may not be floating point\n", eventid); 1002 + return; 1003 + } 999 1004 1000 1005 mon_event_all[eventid].any_cpu = any_cpu; 1006 + mon_event_all[eventid].binary_bits = binary_bits; 1001 1007 mon_event_all[eventid].enabled = true; 1002 1008 } 1003 1009
+2 -1
include/linux/resctrl.h
··· 412 412 u32 resctrl_arch_system_num_rmid_idx(void); 413 413 int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid); 414 414 415 - void resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu); 415 + void resctrl_enable_mon_event(enum resctrl_event_id eventid, bool any_cpu, 416 + unsigned int binary_bits); 416 417 417 418 bool resctrl_is_mon_event_enabled(enum resctrl_event_id eventid); 418 419