Полезная программа не обязательно должна быть большой, верно? Пусть у нас есть процессы, для которых известно время их начала и окончания.
Таких в любой системе пруд пруди.
Такой же Хранилище журнала выполнения в MS SQL Reporting Server, SQL Server Profiler Trace, а также множество пользовательских метрик, которые есть у каждого.
Как осуществляются эти процессы? Спокойно, один за другим, хотят ли они идти все в ногу? Какова средняя и максимальная степень параллелизма этих процессов? Хотелось бы получить что-то вроде этого (процессы показаны черточками вверху):
Мы пишем на SQL?
Решение можно написать на SQL, но получается ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ с выбором вариантов пересечения.Сложность этого составляет O(n^2), а при 100 000 записей (10^10 вариантов) анализ становится практически невозможным.
Решение
Задачу можно решить на традиционном языке практически за линейное время, если данные отсортировать по столбцу времени начала процесса.Если количество «слоев» не очень велико, то все решается за один проход. Прикрепленная программа получает на вход csv-файл (первая строка — заголовок), где должны быть столбцы с временем начала и окончания процесса в формате гггг/мм/дд чч:мм:сс (Формат ячеек -> Пользовательский) Файл должен быть отсортирован по дате начала процесса (если это не так, программа откажется его обрабатывать).
Запустим:
Второй и третий параметры — это номера столбцов с датой/временем начала и окончания процесса.
Нумерация начинается с нуля.
Файлы создаются: секунды.
csv - параллелизм для каждой секунды в обнаруженном диапазоне дат:
Далее рассчитываются агрегаты для более крупных периодов времени и для них рассчитываются максимальные и средние значения:
И вуаля, построим график:
А вот собственно код (еще раз извините, что маленькая программа, но для анализа многих вещей было очень полезно):
Теги: #python #Администрирование сервера #Администрирование баз данных #Microsoft SQL Server #диаграммы #степень параллелизмаimport os import sys import csv import numpy as np from datetime import datetime, timedelta if len(sys.argv) != 4: print ('Usage: python parr.py yourfile.csv colstartn colendn') print (' column numbers are counted from 0') print (' start and end columns must be in format yyyy/mm/dd hh:mm:ss') exit() csvfile = sys.argv[1] start = int(sys.argv[2]) fin = int(sys.argv[3]) prc = [] newprc = [] # check min and max first = True newest = datetime(1980,1,1) oldest = datetime(2030,1,1) prevs = newest with open(csvfile, 'rt', encoding='utf8') as f: reader = csv.reader(f) for r, row in enumerate(reader): if not first: s = datetime.strptime(row[start],"%Y/%m/%d %H:%M:%S") if s<prevs: print('Error: start column is not properly sorted') print(f' Value {s} < previous value {prevs}') exit(1) prevs = s e = datetime.strptime(row[fin],"%Y/%m/%d %H:%M:%S") if e>newest: newest=e if s<oldest: oldest=s first = False print ('Date range: ', oldest, ' - ', newest) seconds = int((newest-oldest).
total_seconds())+1 grid = np.array([], dtype=np.uint16) grid = np.zeros(seconds, dtype=np.uint16).
reshape(seconds) first = True ln = 0 with open(csvfile, 'rt', encoding='utf8') as f: reader = csv.reader(f) for r, row in enumerate(reader): if not first: s = datetime.strptime(row[start],"%Y/%m/%d %H:%M:%S") e = datetime.strptime(row[fin],"%Y/%m/%d %H:%M:%S") # add end time to list of processes prc.append(e) # check what processes stopped before s newprc = [i for i in prc if i >= s] prc = newprc secnum = int((s-oldest).
total_seconds()) duration = int((e-s).
total_seconds()) for k in range(duration): grid[secnum+k] += 1 ln += 1 first = False print(f'Analysis - {ln} points') ln = 0 with open('seconds.csv', 'w') as o: print('Time,processes', file=o) for s in range(seconds): print(f'{oldest+timedelta(seconds=s)},{grid[s]}', file=o) ln += 1 print(f'File seconds.csv - {ln} lines') aggregates = [60,300,900,1800,3600] aggfiles = ['minutes', 'minutes5', 'minutes15', 'minutes30', 'hours'] for aggname in aggfiles: demultiplier = aggregates.pop(0) ln = 0 with open(f'{aggname}.
csv', 'w') as o: print('Time,AvgRuns,MaxRuns', file=o) for m in range(seconds//demultiplier): sm = 0 mx = 0 for s in range(demultiplier): g = grid[m*demultiplier+s] sm += g if mx<g: mx=g print(f'{oldest+timedelta(seconds=m*demultiplier)},{sm/demultiplier},{mx}', file=o) ln += 1 print(f'File {aggname}.
csv - {ln} lines') exit()
-
Макфэдден, Дэниел
19 Oct, 24 -
Эволюция Обзора Спринта В Agile-Команде
19 Oct, 24 -
Как Я Перевел Проект В Бэм... И Перевел
19 Oct, 24