units.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. export function relativeChange(final: number, initial: number): number {
  2. return (final - initial) / initial;
  3. }
  4. /**
  5. * Contains both singular and plural forms of units because the backend currently
  6. * returns different units between profiles and measurements
  7. */
  8. export type ProfilingFormatterUnit =
  9. | 'nanosecond'
  10. | 'nanoseconds'
  11. | 'microsecond'
  12. | 'microseconds'
  13. | 'millisecond'
  14. | 'milliseconds'
  15. | 'second'
  16. | 'seconds'
  17. | 'count'
  18. | 'percent'
  19. | 'percents'
  20. | 'byte'
  21. | 'bytes'
  22. | 'nanojoule'
  23. | 'nanojoules'
  24. | 'watt'
  25. | 'watts';
  26. const durationMappings: Record<ProfilingFormatterUnit, number> = {
  27. nanosecond: 1e-9,
  28. nanoseconds: 1e-9,
  29. microsecond: 1e-6,
  30. microseconds: 1e-6,
  31. millisecond: 1e-3,
  32. milliseconds: 1e-3,
  33. second: 1,
  34. seconds: 1,
  35. count: 1,
  36. percent: 1,
  37. percents: 1,
  38. byte: 1,
  39. bytes: 1,
  40. nanojoule: 1e-9,
  41. nanojoules: 1e-9,
  42. watt: 1,
  43. watts: 1,
  44. };
  45. export function fromNanoJoulesToWatts(nanojoules: number, seconds: number) {
  46. const joules = nanojoules * durationMappings.nanojoules;
  47. return joules / seconds;
  48. }
  49. export function makeFormatTo(
  50. from: ProfilingFormatterUnit | string,
  51. to: ProfilingFormatterUnit | string
  52. ) {
  53. if (durationMappings[from] === undefined) {
  54. throw new Error(`Cannot format unit ${from}, duration mapping is not defined`);
  55. }
  56. if (durationMappings[to] === undefined) {
  57. throw new Error(`Cannot format unit ${from}, duration mapping is not defined`);
  58. }
  59. if (from === to) {
  60. return (v: number) => {
  61. return v;
  62. };
  63. }
  64. return function format(v: number) {
  65. return formatTo(v, from, to);
  66. };
  67. }
  68. export function formatTo(
  69. v: number,
  70. from: ProfilingFormatterUnit | string,
  71. to: ProfilingFormatterUnit | string
  72. ) {
  73. const fromMultiplier = Math.log10(durationMappings[from]);
  74. const toMultiplier = Math.log10(durationMappings[to]);
  75. const value = v * Math.pow(10, fromMultiplier - toMultiplier);
  76. return value;
  77. }
  78. const format = (v: number, abbrev: string, precision: number) => {
  79. if (v === 0) {
  80. return '0' + abbrev;
  81. }
  82. return v.toFixed(precision) + abbrev;
  83. };
  84. export function makeFormatter(
  85. from: ProfilingFormatterUnit | string,
  86. precision: number = 2
  87. ): (value: number) => string {
  88. const multiplier = durationMappings[from];
  89. if (multiplier === undefined) {
  90. throw new Error(`Cannot format unit ${from}, duration mapping is not defined`);
  91. }
  92. if (from === 'count') {
  93. return (value: number) => {
  94. return value.toFixed(precision);
  95. };
  96. }
  97. if (from === 'percent' || from === 'percents') {
  98. return (value: number) => {
  99. return value.toFixed(precision) + '%';
  100. };
  101. }
  102. if (from === 'byte' || from === 'bytes') {
  103. return (value: number) => {
  104. if (value === 0) {
  105. return '0B';
  106. }
  107. const byteUnits = ['B', 'KB', 'MB', 'GB'];
  108. const i = Math.floor(Math.log(value) / Math.log(1000));
  109. if (i < 0) {
  110. return value.toFixed(precision) + byteUnits[0];
  111. }
  112. return (value / Math.pow(1000, i)).toFixed(precision) + byteUnits[i];
  113. };
  114. }
  115. if (from === 'nanojoule' || from === 'nanojoules') {
  116. return (value: number) => {
  117. if (value === 0) {
  118. return '0J';
  119. }
  120. value *= durationMappings[from];
  121. const jouleUnits = ['J', 'kJ', 'MJ', 'GJ'];
  122. const i = Math.floor(Math.log(value) / Math.log(1000));
  123. if (i < 0) {
  124. return value.toFixed(precision) + jouleUnits[0];
  125. }
  126. return (value / Math.pow(1000, i)).toFixed(precision) + (jouleUnits[i] ?? 'J');
  127. };
  128. }
  129. if (from === 'watt' || from === 'watts') {
  130. return (value: number) => {
  131. if (value === 0) {
  132. return '0W';
  133. }
  134. value *= durationMappings[from];
  135. const jouleUnits = ['W', 'kW', 'MW', 'GW'];
  136. const i = Math.floor(Math.log(value) / Math.log(1000));
  137. if (i < 0) {
  138. return value.toFixed(precision) + jouleUnits[0];
  139. }
  140. return (value / Math.pow(1000, i)).toFixed(precision) + jouleUnits[i];
  141. };
  142. }
  143. return (value: number) => {
  144. const duration = value * multiplier;
  145. if (duration >= 1) {
  146. return format(duration, 's', precision);
  147. }
  148. if (duration / 1e-3 >= 1) {
  149. return format(duration / 1e-3, 'ms', precision);
  150. }
  151. if (duration / 1e-6 >= 1) {
  152. return format(duration / 1e-6, 'μs', precision);
  153. }
  154. return format(duration / 1e-9, 'ns', precision);
  155. };
  156. }
  157. function pad(n: number, slots: number) {
  158. return Math.floor(n).toString().padStart(slots, '0');
  159. }
  160. export function makeTimelineFormatter(from: ProfilingFormatterUnit | string) {
  161. const multiplier = durationMappings[from];
  162. if (multiplier === undefined) {
  163. throw new Error(`Cannot format unit ${from}, duration mapping is not defined`);
  164. }
  165. return (value: number) => {
  166. const s = Math.abs(value * multiplier);
  167. const m = s / 60;
  168. const ms = s * 1e3;
  169. return `${value < 0 ? '-' : ''}${pad(m, 2)}:${pad(s % 60, 2)}.${pad(ms % 1e3, 3)}`;
  170. };
  171. }
  172. export function relativeWeight(base: number, value: number) {
  173. // Make sure we dont divide by zero
  174. if (!base || !value) {
  175. return 0;
  176. }
  177. return (value / base) * 100;
  178. }