Necesito calcular el tiempo de ejecución para 2 algoritmos diferentes y luego determinar recomendar uno en función del tiempo de ejecución. Así que soy bastante nuevo en algoritmos y estructuras de datos en general, pero solo en Swift.
Así que he hecho un poco de búsqueda y no he encontrado mucho. Me las arreglé para encontrar esto:
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) { let startTime = CFAbsoluteTimeGetCurrent() operation() let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime print("Time elapsed for \(title): \(timeElapsed) s.") }Esto es entonces lo que realmente estoy tratando de probar:
printTimeElapsedWhenRunningCode(title: "Merge Sort") { let newSort = mergeSort(sortArray) }Ahora no estoy seguro de si esto realmente está calculando lo que estoy necesitando. Luego, cada vez que ejecuto esto siempre obtengo un tiempo diferente. ¿Estoy en el camino correcto?
Nota: en la vida real es mejor encontrar algún marco de prueba de rendimiento establecido. Hacer la prueba de la manera correcta es difícil.
Aquí hay una lista incompleta de cosas que es mejor que hagas si haces tus propias pruebas:
Promedio de muchas iteraciones en lugar de solo una. Hay muchas razones para que los resultados sean un poco ruidosos. Si el tiempo de ejecución total es inferior a 0,1 segundos, lo más probable es que no sea fiable en absoluto. Mejor si es al menos 1 segundo. También tiene sentido realizar un seguimiento no solo del promedio, sino también de otras métricas como el percentil del 95%.
No ignore los resultados del cálculo probado dentro del ciclo. Un compilador inteligente puede optimizar los resultados no utilizados y reemplazarlos con algo como no-op. Idealmente, el resultado no debería ser predecible para el compilador. Como ejemplo: en la i -ésima iteración agregue el i -ésimo (o (i % array.length) -ésimo) elemento de la lista ordenada a la suma total y al final devuelva la suma o imprímala (obviamente fuera de la medida tiempo)
No realice ninguna impresión/registro/IO dentro del algoritmo probado a menos que esté tratando de medir el rendimiento de esa operación de IO. IO es muy lento.
Realice algunas iteraciones de calentamiento antes de las iteraciones principales de "prueba". Esto es para asegurarse de que todos los datos que pueden estar en varios cachés de CPU estén allí. Sin calentamiento, las primeras carreras y las últimas carreras pueden diferir significativamente. Además, si está ejecutando un código administrado (como JavaScript, Java o .Net), muchas ejecuciones pueden obligar a la VM a volver a compilar el código con algunas optimizaciones mejores. En tal caso, es posible que deba ejecutar primero algunos miles de iteraciones de "calentamiento" para forzarlo. Algunos marcos de prueba mejores ejecutan lotes hasta que el tiempo entre diferentes lotes se estabiliza.
Compare el código con el mismo nivel de optimización que se usará en producción. Los compiladores de hoy en día pueden ser muy inteligentes en la optimización si usted los permite y las compilaciones de "depuración" pueden ser fácilmente 10 veces más lentas que las compilaciones de "lanzamiento".
Para ordenar los algoritmos, hay algunas cosas específicas para recordar y la principal es: hacer varias mediciones en diferentes matrices de prueba
Pruebe diferentes tamaños de matriz, desde unos pocos hasta millones de elementos. El acceso a la memoria de hoy es una cosa muy complicada. Diferentes algoritmos tienen diferentes patrones de uso de memoria que pueden afectar en gran medida el rendimiento en diferentes tamaños
Consulta diferentes datos. Algunos algoritmos de clasificación tienen casos patológicamente malos y otros no tienen ninguno. Algunos pueden funcionar especialmente rápido con datos semiordenados y otros no pueden explotarlos. Al menos usa algunos datos aleatorios. Sin embargo, es mejor usar no solo aleatorio.
Si desea comparar el rendimiento, usar el bloque de measure { ... } de las pruebas unitarias es un buen punto de partida, ya que lo ejecuta varias veces y calcula el tiempo transcurrido, la desviación estándar, etc.
También sugeriría:
[Int] en lugar de [String] ) para que se concentre en la velocidad de clasificación en lugar de la velocidad de comparación);Pero para pruebas de rendimiento rápidas, las pruebas unitarias de Xcode son bastante fáciles. Por ejemplo:
class MyAppTests: XCTestCase { let iterationCount = 1_000 // build large array var array = (0 ..< 1_000).map { _ in Int.random(in: 0 ..< 1_000_000) } // test performance func testSortPerformance() { measure { for _ in 0 ..< iterationCount { let results = array.sorted() XCTAssert(!results.isEmpty) } } } func testBubbleSortPerformance() { measure { for _ in 0 ..< iterationCount { let results = array.bubbleSorted() XCTAssert(!results.isEmpty) } } } }Eso producirá los siguientes resultados en el Navegador de informes:
O abajo en la consola, verás los detalles:
/.../MyAppTests.swift:33: Test Case '-[MyAppTests.MyAppTests testBubbleSortPerformance]' measured [Time, seconds] average: 0.603, relative standard deviation: 3.284%, values: [0.613748, 0.580443, 0.590879, 0.586842, 0.626791, 0.610288, 0.595295, 0.588713, 0.594823, 0.647156], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100 /.../MyAppTests.swift:23: Test Case '-[MyAppTests.MyAppTests testSortPerformance]' measured [Time, seconds] average: 0.025, relative standard deviation: 13.393%, values: [0.033849, 0.026869, 0.022752, 0.023048, 0.023024, 0.022847, 0.023286, 0.023987, 0.023803, 0.022640], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100Y, ya que estoy en eso, probablemente también probaría los propios algoritmos de clasificación, por ejemplo, asegurándome de que los resultados fueran valores crecientes y que el total de todos los elementos aún se sumaran:
func testBubbleSort() { let results = array.bubbleSorted() var previous = results[0] for index in 1 ..< results.count { let current = results[index] XCTAssertLessThanOrEqual(previous, current) previous = current } XCTAssertEqual(results.sum(), array.sum()) }