mirror of
				https://github.com/CorentinTh/it-tools.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <n-scrollbar style="flex: 1" x-scrollable>
 | 
						|
    <n-space :wrap="false" style="flex: 1" justify="center" :size="0">
 | 
						|
      <div v-for="(suite, index) of suites" :key="index">
 | 
						|
        <n-card style="width: 292px; margin: 0 8px 5px">
 | 
						|
          <n-form-item label="Suite name:" :show-feedback="false" label-placement="left">
 | 
						|
            <n-input v-model:value="suite.title" placeholder="Suite name..." />
 | 
						|
          </n-form-item>
 | 
						|
 | 
						|
          <n-divider></n-divider>
 | 
						|
          <n-form-item label="Suite values" :show-feedback="false">
 | 
						|
            <dynamic-values v-model:values="suite.data" />
 | 
						|
          </n-form-item>
 | 
						|
        </n-card>
 | 
						|
 | 
						|
        <n-space justify="center">
 | 
						|
          <n-button v-if="suites.length > 1" quaternary @click="suites.splice(index, 1)">
 | 
						|
            <template #icon>
 | 
						|
              <n-icon :component="Trash" depth="3" />
 | 
						|
            </template>
 | 
						|
            Delete suite
 | 
						|
          </n-button>
 | 
						|
          <n-button quaternary @click="suites.splice(index + 1, 0, { data: [0], title: `Suite ${suites.length + 1}` })">
 | 
						|
            <template #icon>
 | 
						|
              <n-icon :component="Plus" depth="3" />
 | 
						|
            </template>
 | 
						|
            Add suite
 | 
						|
          </n-button>
 | 
						|
        </n-space>
 | 
						|
      </div>
 | 
						|
    </n-space>
 | 
						|
    <br />
 | 
						|
  </n-scrollbar>
 | 
						|
 | 
						|
  <div style="flex: 0 0 100%">
 | 
						|
    <div style="max-width: 600px; margin: 0 auto">
 | 
						|
      <n-space justify="center">
 | 
						|
        <n-form-item label="Unit:" label-placement="left">
 | 
						|
          <n-input v-model:value="unit" placeholder="Unit (eg: ms)" />
 | 
						|
        </n-form-item>
 | 
						|
 | 
						|
        <n-button
 | 
						|
          tertiary
 | 
						|
          @click="
 | 
						|
            suites = [
 | 
						|
              { title: 'Suite 1', data: [] },
 | 
						|
              { title: 'Suite 2', data: [] },
 | 
						|
            ]
 | 
						|
          "
 | 
						|
          >Reset suites</n-button
 | 
						|
        >
 | 
						|
      </n-space>
 | 
						|
 | 
						|
      <n-table>
 | 
						|
        <thead>
 | 
						|
          <tr>
 | 
						|
            <th>{{ header.position }}</th>
 | 
						|
            <th>{{ header.title }}</th>
 | 
						|
            <th>{{ header.size }}</th>
 | 
						|
            <th>{{ header.mean }}</th>
 | 
						|
            <th>{{ header.variance }}</th>
 | 
						|
          </tr>
 | 
						|
        </thead>
 | 
						|
        <tbody>
 | 
						|
          <tr v-for="{ title, size, mean, variance, position } of results" :key="title">
 | 
						|
            <td>{{ position }}</td>
 | 
						|
            <td>{{ title }}</td>
 | 
						|
            <td>{{ size }}</td>
 | 
						|
            <td>{{ mean }}</td>
 | 
						|
            <td>{{ variance }}</td>
 | 
						|
          </tr>
 | 
						|
        </tbody>
 | 
						|
      </n-table>
 | 
						|
      <br />
 | 
						|
      <n-space justify="center">
 | 
						|
        <n-button tertiary @click="copyAsMarkdown">Copy as markdown table</n-button>
 | 
						|
        <n-button tertiary @click="copyAsBulletList">Copy as bullet list</n-button>
 | 
						|
      </n-space>
 | 
						|
    </div>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script setup lang="ts">
 | 
						|
import { Trash, Plus } from '@vicons/tabler';
 | 
						|
import { useClipboard, useStorage } from '@vueuse/core';
 | 
						|
import _ from 'lodash';
 | 
						|
import { computed } from 'vue';
 | 
						|
import { computeAverage, computeVariance, arrayToMarkdownTable } from './benchmark-builder.models';
 | 
						|
import DynamicValues from './dynamic-values.vue';
 | 
						|
 | 
						|
const suites = useStorage('benchmark-builder:suites', [
 | 
						|
  { title: 'Suite 1', data: [5, 10] },
 | 
						|
  { title: 'Suite 2', data: [8, 12] },
 | 
						|
]);
 | 
						|
 | 
						|
const unit = useStorage('benchmark-builder:unit', '');
 | 
						|
 | 
						|
const round = (v: number) => Math.round(v * 1000) / 1000;
 | 
						|
 | 
						|
const results = computed(() => {
 | 
						|
  return suites.value
 | 
						|
    .map(({ data: dirtyData, title }) => {
 | 
						|
      const data = dirtyData.filter(_.isNumber);
 | 
						|
 | 
						|
      return {
 | 
						|
        title,
 | 
						|
        size: data.length,
 | 
						|
        mean: computeAverage({ data }),
 | 
						|
        variance: computeVariance({ data }),
 | 
						|
      };
 | 
						|
    })
 | 
						|
    .sort((a, b) => a.mean - b.mean)
 | 
						|
    .map(({ mean, variance, size, title }, index, suites) => {
 | 
						|
      const cleanUnit = unit.value.trim();
 | 
						|
      const bestMean: number = suites[0].mean;
 | 
						|
      const deltaWithBestMean = mean - bestMean;
 | 
						|
      const ratioWithBestMean = bestMean === 0 ? '∞' : round(mean / bestMean);
 | 
						|
 | 
						|
      const comparisonValues: string =
 | 
						|
        index !== 0 && bestMean !== mean ? ` (+${round(deltaWithBestMean)}${cleanUnit} ; x${ratioWithBestMean})` : '';
 | 
						|
 | 
						|
      return {
 | 
						|
        position: index + 1,
 | 
						|
        title,
 | 
						|
        mean: `${round(mean)}${cleanUnit}${comparisonValues}`,
 | 
						|
        variance: `${round(variance)}${cleanUnit}${cleanUnit ? '²' : ''}`,
 | 
						|
        size,
 | 
						|
      };
 | 
						|
    });
 | 
						|
});
 | 
						|
 | 
						|
const { copy } = useClipboard();
 | 
						|
 | 
						|
const header = {
 | 
						|
  title: 'Suite',
 | 
						|
  size: 'Samples',
 | 
						|
  mean: 'Mean',
 | 
						|
  variance: 'Variance',
 | 
						|
  position: 'Position',
 | 
						|
};
 | 
						|
 | 
						|
function copyAsMarkdown() {
 | 
						|
  copy(arrayToMarkdownTable({ data: results.value, headerMap: header }));
 | 
						|
}
 | 
						|
 | 
						|
function copyAsBulletList() {
 | 
						|
  const bulletList = results.value
 | 
						|
    .flatMap(({ title, ...sections }) => {
 | 
						|
      return [
 | 
						|
        ` - ${title}`,
 | 
						|
        ...Object.entries(sections).map(
 | 
						|
          ([key, value]) => `    - ${header[key as keyof typeof header] ?? key}: ${value}`,
 | 
						|
        ),
 | 
						|
      ];
 | 
						|
    })
 | 
						|
    .join('\n');
 | 
						|
 | 
						|
  copy(bulletList);
 | 
						|
}
 | 
						|
</script>
 | 
						|
 | 
						|
<style lang="less" scoped></style>
 |