Ich habe von jemandem gehört, dass "malloc langsam ist, daher ist es schneller, Speicher zu speichern und wiederzuverwenden." Wenn du es wirklich tun willst, musst du es sperren, nicht wahr? Während des Denkens scheint es besser, einen Rapper zu machen, wenn es wahr ist. So etwas kann nicht geholfen werden, selbst wenn Sie die Theorie auf dem Schreibtisch fortsetzen. Lassen Sie uns sie also tatsächlich messen! ** ** **
Dieses Mal ** werde ich einen wiederholten Test von calloc / free für die folgenden 4 Typen und Maßnahmen durchführen **. Ich habe mich für Calloc entschieden, weil ich es persönlich öfter benutze. Ich bedauere, dass Malloc rein genauer ist
Die Bibliothek bestimmt einfach die Größe und Größe des zu speichernden Speichers. Als Vorhersage vor der Messung sind 2 und 3 schnell, wenn sie innerhalb der Speichernutzung und -größe liegen, und außerhalb dieses Bereichs ist 1 eine gute Übereinstimmung, 4 nicht. Was wird jetzt passieren
Lassen Sie die Init-Funktion aufrufen und erstellen Sie dort eine Speicherliste. Die Liste verfügt über ein verwendetes / nicht verwendetes Flag, das während des Aufrufs nicht verwendeten Speicher weiterleitet und diese Daten an das Ende der Liste (Ende) verschiebt. Auf diese Weise wird der erste Kopf immer nicht verwendet und der Schwanz verwendet Speicherdaten.
Im Gegensatz dazu werden die verwendeten Speicherdaten, wenn sie frei sind, vom Ende aus durchsucht, um festzustellen, ob sie mit den frei verfügbaren Daten übereinstimmen. Übereinstimmungen werden nicht freigegeben, sondern in nicht verwendete geändert und an den Anfang verschoben.
Da die Positionen von Kopf und Schwanz in Erinnerung bleiben, mache ich mir Sorgen um die Suche, wenn ich frei bin, aber ansonsten kann ich die Erinnerung sofort weitergeben. Ist es nicht ein gutes Gefühl! ??
Nachtrag 2018/08 Ich habe es zu einer Bibliothek gemacht. Dieser Mempool.
Der Hals der obigen Hülle ist immer noch das Verhalten, wenn er frei ist. Wenn fast alle Speicherdaten verwendet werden, müssen fast alle Daten durchsucht werden. Ich habe mich gefragt, ob ich die Struktur der Suchliste überprüfen muss, aber ich habe einen guten Schritt gefunden. Diese Seite, meine Hand wird als schlechte Antwort eingeführt. Lol Wenn Sie hier die Bedingung für die letzte richtige Antwort festlegen: "** Die Größe des Speicherbereichs ist gleich und es ist ein Quadratbyte von 2. **", kann die Position sofort durch Bitberechnung erfasst werden. Es ist wundervoll!
Basierend auf dem oben Gesagten haben wir den Wrapper überprüft, der zum Engpass wird.
Zunächst am Anfang. Die Liste und die Speicherentität werden in einer Reihe angeordnet. Darüber hinaus ist die Größenangabe auf 2 Bytes begrenzt. Dann werden die Speicherentitäten wie folgt in Vielfachen von 2 ^ x aneinandergereiht. Wenn Sie also die Bits x-mal verschieben, wenn sie frei sind, können Sie die Position finden.
Was passiert nun, wenn Sie frei sind? Zunächst können Sie anhand des Adressbereichs der zuerst erstellten Speicherentität erkennen, ob sich die frei zu speichernde Speicherentität in der Verwaltung befindet. Sie müssen also nicht jedes Mal wie beim ersten Wrapper eine vollständige Suche durchführen. Gegebenenfalls auch Bitverschiebung, um die Position anzugeben. ⇒ Nehmen Sie die entsprechende Listendatenentität heraus und verschieben Sie sie in den Kopf. Der Suchvorgang wird nicht mehr benötigt. Ist das nicht schneller?
Außerdem habe ich auf Code zum Finden dieser Bitposition verwiesen, um die x-Zeit-Bitverschiebung zu erhalten. Da es nur zum Zeitpunkt der Initialisierung verwendet wird, ist es nicht an dieser Messung beteiligt, aber es ist auch erstaunlich, dass ich keine Zeit brauche, um hart an der Bitverschiebung bis zum Ende zu arbeiten.
Ich dachte, dass dieser Bereich meine Grenze ist, also werde ich ihn messen.
Das Messwerkzeug und der Quellcode befinden sich unten. https://github.com/developer-kikikaikai/speedtest
Nach dem Erstellen können Sie messen, indem Sie run.rb in sample / mallocspeed ausführen.
Bitten Sie die Erstellungsbibliothek, 1024 bis 1024 Byte Speicher zu speichern. Unter diesen Bedingungen werden die folgenden Messungen 50 Mal, 100 Mal, 1024 Mal und 10000 Mal 10 Mal durchgeführt, und die Gesamtzeit wird ausgegeben.
Die Zeitmessung erfolgt in der Speedtest-Bibliothek. (Da das zeitgesteuerte Protokoll im Speicher abgelegt und am Ende angezeigt wird, ist der Overhead aufgrund der Messung meiner Meinung nach nicht so hoch.
Linux Ubuntu 18.04 Speicher 8 GByte 4 CPUs (auf VM)
Beschreibung | Bedeutung |
---|---|
Aktionsspalte | Welche Messung ist dargestellt |
Gesamtzeitspalte | Gesamtzeit.-3 ist 0.001(1/10^3)meint |
XXX calloc(calloc/free under initial size) | 1024 Byte Malloc/freie Messung |
XXX calloc(calloc/free initial size+over size) | 1024byte*2 und 1024 Byte Malloc/freie Messung |
XXX=normal | Gewöhnlicher Calloc/free(Wird unten wie gewohnt beschrieben) |
XXX=wrap | Erster Wrapper |
XXX=hhs_calloc | Version zur Beseitigung von Engpässen(Unten hhs_Beschrieben als Calloc) |
XXX=tc_calloc | tc_calloc/tc_Verwenden Sie kostenlos(Unten tc_Beschrieben als Calloc) |
** 50 mal x 10 Messungen **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.15806e-3 |
wrap calloc code(calloc/free under initial size) | 0.75032e-4 |
hhs_calloc(calloc/free under initial size) | 0.135938e-3 |
tc_calloc(calloc/free under initial size) | 0.186022e-3 |
normal calloc(calloc/free initial size+over size) | 0.711725e-3 |
wrap calloc(calloc/free initial size+over size) | 0.487427e-3 |
hhs_calloc(calloc/free initial size+over size) | 0.443236e-3 |
tc_calloc(calloc/free initial size+over size) | 0.702283e-3 |
Zwei Wrapper sind schnell, während die Anzahl klein ist. Der erste Wrapper ist besonders stark, wenn er sich nur in Reichweite befindet. Wenn die Größe übergroß ist, ist hhs_calloc bereits gut. Ist nicht beides gut?
(Titel 1 und 2 sind unten weggelassen)
** 100 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.283713e-3 |
wrap calloc code(calloc/free under initial size) | 0.153599e-3 |
hhs_calloc(calloc/free under initial size) | 0.272328e-3 |
tc_calloc(calloc/free under initial size) | 0.293742e-3 |
normal calloc(calloc/free initial size+over size) | 0.1394836e-2 |
wrap calloc(calloc/free initial size+over size) | 0.1395083e-2 |
hhs_calloc(calloc/free initial size+over size) | 0.1244906e-2 |
tc_calloc(calloc/free initial size+over size) | 0.1337618e-2 |
Es ist immer noch ungefähr 1/10 der maximalen Anzahl von Registrierungen, aber die Geschwindigkeit des ersten Wrappers ist hier bereits stark gesunken. Dieser Bereich ist eine Ebene, in der sich das Ranking bei jeder Ausführung ändert.
** 500 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.1453858e-2 |
wrap calloc code(calloc/free under initial size) | 0.301273e-2 |
hhs_calloc(calloc/free under initial size) | 0.1291004e-2 |
tc_calloc(calloc/free under initial size) | 0.13424e-2 |
normal calloc(calloc/free initial size+over size) | 0.7863012e-2 |
wrap calloc(calloc/free initial size+over size) | 0.44953204e-1 |
hhs_calloc(calloc/free initial size+over size) | 0.6339118e-2 |
tc_calloc(calloc/free initial size+over size) | 0.6493924e-2 |
Mit etwa der Hälfte der maximalen Anzahl von Registrierungen war der erste Wrapper bei weitem der langsamste. Schneller aussteigen als ich erwartet hatte (-_-;) Auch die Leistung von tc_calloc hebt sich von diesem Bereich ab.
** 1024 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.2824874e-2 |
wrap calloc code(calloc/free under initial size) | 0.20755398e-1 |
hhs_calloc(calloc/free under initial size) | 0.2560653e-2 |
tc_calloc(calloc/free under initial size) | 0.2751811e-2 |
normal calloc(calloc/free initial size+over size) | 0.16774762e-1 |
wrap calloc(calloc/free initial size+over size) | 0.54582233e-1 |
hhs_calloc(calloc/free initial size+over size) | 0.13983322e-1 |
tc_calloc(calloc/free initial size+over size) | 0.14046191e-1 |
Gerade die maximale Anzahl von Registrierungen erreicht. Hhhs_calloc gibt sein Bestes, selbst wenn unerwartet außerhalb des Bereichs gemischt wird.
** 10000 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.30325826e-1 |
wrap calloc code(calloc/free under initial size) | 0.5094687e-1 |
hhs_calloc(calloc/free under initial size) | 0.30124209e-1 |
tc_calloc(calloc/free under initial size) | 0.26917778e-1 |
normal calloc(calloc/free initial size+over size) | 0.176232715e0 |
wrap calloc(calloc/free initial size+over size) | 0.221244686e0 |
hhs_calloc(calloc/free initial size+over size) | 0.176962985e0 |
tc_calloc(calloc/free initial size+over size) | 0.146961605e0 |
Schließlich ist tc_calloc oben. Es scheint, dass je mehr die Zahl, desto mächtiger sie ist. Zu diesem Zeitpunkt unterscheidet sich hhs_calloc nicht von normalem Calloc, daher versuche ich nur mein Bestes, um mit einem Vorteil von bis zu 1024 Mal zu entkommen.
Dieses Ergebnis war interessant, also werde ich es veröffentlichen. Es ist bereits ein Messexperiment von tc_malloc. Da jedes calloc / free von tc_malloc überschrieben wird, ist jedes Ergebnis länger als das erste.
** 50 mal x 10 Messungen **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.14662e-3 |
wrap calloc code(calloc/free under initial size) | 0.7501e-4 |
hhs_calloc(calloc/free under initial size) | 0.14337e-3 |
tc_calloc(calloc/free under initial size) | 0.22985e-4 |
normal calloc(calloc/free initial size+over size) | 0.803501e-3 |
wrap calloc(calloc/free initial size+over size) | 0.28677e-3 |
hhs_calloc(calloc/free initial size+over size) | 0.271435e-3 |
tc_calloc(calloc/free initial size+over size) | 0.117837e-3 |
Hier ist tc_calloc schon bei weitem das Beste. Ich dachte, es wäre ungefähr das gleiche wie Calloc / Free, das komplett verpackt war, aber ich war überrascht.
** 100 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.27454e-3 |
wrap calloc code(calloc/free under initial size) | 0.147085e-3 |
hhs_calloc(calloc/free under initial size) | 0.270945e-3 |
tc_calloc(calloc/free under initial size) | 0.43941e-4 |
normal calloc(calloc/free initial size+over size) | 0.1559897e-2 |
wrap calloc(calloc/free initial size+over size) | 0.759443e-3 |
hhs_calloc(calloc/free initial size+over size) | 0.489991e-3 |
tc_calloc(calloc/free initial size+over size) | 0.255653e-3 |
Die Geschwindigkeit von tc_calloc ist unvermindert. Davon abgesehen ändert sich nichts. Geschwindigkeiten außerhalb des Bereichs werden durch Calloc / Free-Overwrites beeinflusst, und Wrapper sind schneller.
** 500 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.1373838e-2 |
wrap calloc code(calloc/free under initial size) | 0.1687707e-2 |
hhs_calloc(calloc/free under initial size) | 0.1296464e-2 |
tc_calloc(calloc/free under initial size) | 0.262718e-3 |
normal calloc(calloc/free initial size+over size) | 0.7076653e-2 |
wrap calloc(calloc/free initial size+over size) | 0.13166146e-1 |
hhs_calloc(calloc/free initial size+over size) | 0.2556278e-2 |
tc_calloc(calloc/free initial size+over size) | 0.1392622e-2 |
Ganz zu schweigen von tc_calloc. In Anbetracht des ersten Ergebnisses gibt hhs_calloc sein Bestes.
** 1024 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.2763511e-2 |
wrap calloc code(calloc/free under initial size) | 0.6518494e-2 |
hhs_calloc(calloc/free under initial size) | 0.2707665e-2 |
tc_calloc(calloc/free under initial size) | 0.561575e-3 |
normal calloc(calloc/free initial size+over size) | 0.14081652e-1 |
wrap calloc(calloc/free initial size+over size) | 0.16251563e-1 |
hhs_calloc(calloc/free initial size+over size) | 0.4127922e-2 |
tc_calloc(calloc/free initial size+over size) | 0.3438721e-2 |
Es wird gesagt, dass sich der Unterschied innerhalb des Bereichs vergrößern wird, in dem der Rapper gut sein sollte. Ich denke, tc_calloc nutzt den Speicher auch gut.
** 10000 mal x 10 **
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.27661637e-1 |
wrap calloc code(calloc/free under initial size) | 0.18210164e-1 |
hhs_calloc(calloc/free under initial size) | 0.12308628e-1 |
tc_calloc(calloc/free under initial size) | 0.9218671e-2 |
normal calloc(calloc/free initial size+over size) | 0.148160442e0 |
wrap calloc(calloc/free initial size+over size) | 0.84871154e-1 |
hhs_calloc(calloc/free initial size+over size) | 0.68569389e-1 |
tc_calloc(calloc/free initial size+over size) | 0.65872532e-1 |
Es scheint eine Bibliothek zu geben, die schneller ist als das Feld, das ich vorbereitet habe. Der Onkel, der es geschaffen hat, ist traurig.
Das Obige war ein einfacher Vergleich, daher werden wir dieses Mal ein Szenario erstellen, das auf dem Anwendungsfall der Anwendung basiert, über die wir nachdenken.
Die Zielanwendung ist "Multithreading von ligttpd". Also werde ich mit dieser Annahme messen.
Damit
Element | Bedingungen |
---|---|
Speicherpool | 10 Clients ⇒ 4096 Bytes x 256 x 10 gepoolt |
Testfall | 10 aller Clients sind verbunden. Nachdem Sie so viel Speicher zugewiesen haben, wird die Freigabe wiederholt. * Da der Zeitpunkt für die Rückgabe der Antwort des Kunden unterschiedlich ist, ändern Sie die Freigabereihenfolge entsprechend. |
Angenommen alle verbundenen Clients | 2000 (10,000 scheint Zeit zu brauchen, also hör auf) |
Unter diesen Bedingungen wird jede Messung fünfmal durchgeführt und die Gesamtzeit ausgegeben.
Call 5 times, input is 512000
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.2694234765e1 |
wrap calloc code(calloc/free under initial size) | 0.27786253728e2 |
hhs_calloc(calloc/free under initial size) | 0.673090478e0 |
tc_calloc(calloc/free under initial size) | 0.617789121e0 |
hhs_calloc> = tc_calloc> Normal> Erster Wrapper
Die ersten beiden Ebenen sind Ebenen, in denen sich die Reihenfolge abhängig vom Ausführungszeitpunkt ändert
Call 5 times, input is 512000
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.593853921e0 |
wrap calloc code(calloc/free under initial size) | 0.4174470792e1 |
hhs_calloc(calloc/free under initial size) | 0.6199698e0 |
tc_calloc(calloc/free under initial size) | 0.592267608e0 |
tc_calloc> = normal> = hhs_calloc> erster Wrapper
Die vorherigen drei Ebenen waren Ebenen, in denen die Reihenfolge bei jeder Ausführung geändert wurde. In diesem Ergebnis wirkt sich das durch tc_malloc ersetzte Calloc jedoch auf hhs_calloc aus. Vergleichen Sie noch einmal mit nur der tc_calloc-Messung von tc_malloc.
Action | Total time |
---|---|
normal calloc(calloc/free under initial size) | 0.2694234765e1 |
wrap calloc code(calloc/free under initial size) | 0.27786253728e2 |
hhs_calloc(calloc/free under initial size) | 0.673090478e0 |
tc_calloc(calloc/free under initial size) | 0.592267608e0 |
hhs_calloc> tc_calloc> Normal> Erster Wrapper
Wenn man es so betrachtet, kann hhs_calloc interessant sein, wenn es gut eingestellt ist.
2018/06/10 Ich war neugierig auf die Kommentare und habe auch versucht, hhs_calloc freizuschalten. Vergleichen Sie Seite an Seite mit den Ergebnissen von tc_calloc.
Action | Total time |
---|---|
hhs_calloc(calloc/free under initial size) | 0.589852316e0 |
tc_calloc(calloc/free under initial size) | 0.592267608e0 |
Oh, der Datensatz ändert sich jedes Mal, wenn Sie messen, aber wenn es keine Sperre gibt, kann hhs_calloc gewinnen. Es ist interessant, wenn Sie die Threads richtig verwenden!
――Es ist wahr, dass ** malloc / free schneller ist, wenn Sie entscheiden, wie Sie es verwenden und es je nach Situation gut einwickeln **. Wenn Sie die Geschwindigkeit jedoch nicht ernsthaft berücksichtigen, wird sie langsamer.
Übrigens habe ich die Speichernutzung nicht gesehen. Wenn der Speicherbedarf von tc_malloc sehr hoch ist, möchten Sie möglicherweise Ihren eigenen Wrapper erstellen.
Referenz zur Beseitigung von Engpässen Wie man eine große Anzahl von Hochgeschwindigkeits- und speichereffizienten Sätzen unter Verwendung eines großen Speicherausrichtungsbereichs realisiert
Bitverschiebungsreferenz ■ [C #] "Erstaunlicher" Code zum Finden der am weitesten rechts stehenden Bitposition
Messung: Zur Untersuchung der Rubinverarbeitung und des Gleitkommas bei der Summierung der Ergebnisse Über Brüche, Float und BigDecimal von Ruby ... (für Anfänger)
Recommended Posts