Ich habe gerade ~ 1 Milliarde als Zählung für ein z-index
CSS verwendet und überlegte, welche Vergleiche durchgeführt werden müssen. Gibt es einen Leistungsunterschied auf ALU-Ebene bei Vergleichen zwischen sehr großen und sehr kleinen Zahlen?
Wäre zum Beispiel einer dieser beiden Schnipsel teurer als der andere?
snippet 1
for (int i = 0; i < 10000000; i++){
if (i < 10000000000000) {
//do nothing
}
}
snippet 2
for (int i = 0; i < 10000000; i++){
if (i < 1000) {
//do nothing
}
}
performance
cpu
Viziionary
quelle
quelle
CMP
Maschinenbefehle langsamer sind, wenn siei
größer sind.Antworten:
Jeder Prozessor, an dem ich gearbeitet habe, führt einen Vergleich durch, indem er einen der Operanden vom anderen subtrahiert, das Ergebnis verwirft und die Flags des Prozessors (Null, Negativ usw.) in Ruhe lässt. Da die Subtraktion als einzelne Operation ausgeführt wird, spielt der Inhalt der Operanden keine Rolle.
Der beste Weg, um die Frage sicher zu beantworten, besteht darin, Ihren Code in Assembly zu kompilieren und die generierten Anweisungen in der Dokumentation des Zielprozessors zu finden. Für aktuelle Intel-CPUs wäre dies das Intel 64- und IA-32-Architekturen-Software-Entwicklerhandbuch .
Die Beschreibung der
CMP
Anweisung ("compare") befindet sich in Band 2A, Seite 3-126 oder Seite 618 der PDF-Datei und beschreibt ihre Funktionsweise als:Dies bedeutet, dass der zweite Operand bei Bedarf vorzeichenerweitert, vom ersten Operanden subtrahiert und das Ergebnis in einem temporären Bereich im Prozessor abgelegt wird. Dann werden die Status-Flags genauso gesetzt wie bei der
SUB
Anweisung ("subtrahieren") (Seite 1492 der PDF).In der Dokumentation
CMP
oder wird nichtSUB
erwähnt, dass sich die Werte der Operanden auf die Latenz auswirken. Daher ist jeder Wert, den Sie verwenden, sicher.quelle
Es ist sehr unwahrscheinlich, es sei denn, der Wechsel von einer kleinen zu einer großen Zahl ändert Ihren numerischen Typ, beispielsweise von einem
int
zu einemlong
. Selbst dann ist der Unterschied möglicherweise nicht signifikant. Es ist wahrscheinlicher, dass Sie einen Unterschied feststellen, wenn Ihre Programmiersprache unbemerkt auf Arithmetik mit willkürlicher Genauigkeit umschaltet .Ihr Compiler führt jedoch möglicherweise einige clevere Optimierungen durch, die Ihnen nicht bekannt sind. Der Weg, den Sie herausfinden, ist zu messen. Führen Sie einen Profiler für Ihren Code aus. Sehen Sie, welche Vergleiche am längsten dauern. Oder starten und stoppen Sie einfach einen Timer.
quelle
Viele Prozessoren haben "kleine" Befehle, mit denen arithmetische Operationen, einschließlich Vergleiche, an bestimmten unmittelbar angegebenen Operanden ausgeführt werden können. Andere Operanden als diese speziellen Werte müssen entweder ein größeres Befehlsformat oder in einigen Fällen einen Befehl "Wert aus dem Speicher laden" verwenden. Im ARM Cortex-M3-Befehlssatz gibt es beispielsweise mindestens fünf Möglichkeiten, wie ein Wert mit einer Konstanten verglichen werden kann:
Die erste Form ist die kleinste; Die zweite und dritte Form können je nach der Geschwindigkeit des Speichers, aus dem Code abgerufen wird, so schnell ausgeführt werden oder auch nicht. Die vierte Form ist mit ziemlicher Sicherheit langsamer als die ersten drei und die fünfte Form sogar langsamer, aber die letztere kann mit jedem 32-Bit-Wert verwendet werden.
Auf älteren x86-Prozessoren werden Vergleichsbefehle in Kurzform schneller ausgeführt als in Langform. Viele neuere Prozessoren konvertieren jedoch sowohl die Langform als auch die Kurzform in dieselbe Darstellung, wenn sie zum ersten Mal abgerufen werden, und speichern diese einheitliche Darstellung im Cache. Während eingebettete Controller (wie sie auf vielen mobilen Plattformen zu finden sind) einen Geschwindigkeitsunterschied aufweisen, sind dies bei vielen x86-basierten Computern nicht der Fall.
Beachten Sie auch, dass in vielen Fällen, in denen eine Konstante häufig in einer Schleife verwendet wird, ein Compiler die Konstante nur einmal in ein Register laden muss, bevor die Schleife startet. Andererseits gibt es einige Situationen, selbst in kleinen Schleifen, in denen dies nicht immer der Fall ist. Wenn eine Schleife klein ist, aber stark ausgeführt wird, kann es gelegentlich zu einer größeren Leistung zwischen Vergleichen mit kurzen Sofortwerten und Vergleichen mit längeren Werten kommen.
quelle
Die kurze Antwort auf diese Frage lautet: Nein , es gibt keinen Zeitunterschied, um zwei Zahlen basierend auf der Größe dieser Zahlen zu vergleichen, sofern sie im selben Datentyp gespeichert sind (z. B. beide 32-Bit-Ints oder beide 64-Bit-Longs).
Darüber hinaus ist es bis zur Wortgröße der ALU unglaublich unwahrscheinlich, dass der Vergleich zweier ganzer Zahlen jemals mehr als einen Taktzyklus in Anspruch nimmt, da dies eine triviale Operation ist, die einer Subtraktion entspricht. Ich denke, jede Architektur, mit der ich mich jemals befasst habe, hatte einen Ganzzahlvergleich mit einem Zyklus.
Die einzigen Fälle, an die ich denken kann, bei denen ein Vergleich zweier Zahlen keine Einzeltaktoperation war, sind die folgenden:
quelle
@ RobertHarveys Antwort ist gut; Betrachten Sie diese Antwort als Ergänzung zu seiner.
Sie sollten auch die Branchenvorhersage berücksichtigen :
Wenn in Ihrem Beispiel die
if
Anweisung in der Schleife immer dieselbe Antwort zurückgibt, kann das System sie optimieren, indem es richtig errät, in welche Richtung sie verzweigt. Da in Ihrem Beispiel dieif
Anweisung im ersten Fall immer das gleiche Ergebnis zurückgibt, wird sie etwas schneller ausgeführt als im zweiten Fall.Ausgezeichnete Stapelüberlauffrage zum Thema
quelle
Das hängt von der Implementierung ab, ist aber sehr, sehr unwahrscheinlich .
Ich gebe zu, dass ich die Implementierungsdetails der verschiedenen Browser-Engines nicht durchgelesen habe und CSS keinen bestimmten Speichertyp für Zahlen spezifiziert. Ich bin jedoch der Meinung, dass davon ausgegangen werden kann, dass alle gängigen Browser 64-Bit-Gleitkommazahlen mit doppelter Genauigkeit ("Doubles") verwenden, um einen Begriff aus C / C ++ auszuleihen und die meisten ihrer numerischen Anforderungen in CSS zu erfüllen , weil JavaScript dies für Zahlen verwendet und daher die Integration durch Verwendung desselben Typs erleichtert.
Vom Standpunkt des Computers aus tragen alle Doubles dieselbe Datenmenge: 64 Bit, unabhängig davon, ob der Wert 1 oder -3,14 oder 1000000 oder 1e100 ist . Die Zeit, die für eine Operation mit diesen Zahlen benötigt wird, hängt nicht vom tatsächlichen Wert dieser Zahlen ab, da immer dieselbe Datenmenge verarbeitet wird. Es ist ein Kompromiss, Dinge auf diese Weise zu tun, da Doppelte nicht alle Zahlen (oder sogar alle Zahlen in ihrem Bereich) genau darstellen können, aber für die meisten Angelegenheiten nahe genug kommen können und die Art der Dinge, die CSS nicht numerisch tut -Anforderung genug, um mehr Präzision als das zu brauchen. Kombinieren Sie dies mit den Vorteilen der direkten Kompatibilität mit JavaScript, und Sie haben ein ziemlich starkes Argument für Doppel.
Es ist nicht unmöglich, dass jemand CSS mithilfe einer Codierung variabler Länge für Zahlen implementiert. Wenn jemand eine Codierung mit variabler Länge verwendet, dann gegen kleine Zahlen zu vergleichen wäre weniger teuer als Vergleich gegen eine große Zahl, weil eine große Zahl mehr Daten knirschen . Diese Art der Codierung kann präziser als die Binärcodierung sein, sie ist jedoch auch viel langsamer, und insbesondere für CSS reichen die Genauigkeitsgewinne wahrscheinlich nicht aus, um den Leistungseffekt zu erzielen. Ich wäre sehr überrascht zu erfahren, dass jeder Browser die Dinge so gemacht hat.
Theoretisch gibt es zu allem, was ich oben gesagt habe, eine mögliche Ausnahme: Der Vergleich mit Null ist oft schneller als der Vergleich mit anderen Zahlen . Das liegt nicht daran, dass Null kurz ist (wenn das der Grund wäre, dann sollte 1 genauso schnell sein, aber es ist nicht so). Es liegt daran, dass Sie mit Null betrügen können. Es ist die einzige Zahl, bei der alle Bits deaktiviert sind. Wenn Sie also wissen, dass einer der Werte Null ist, müssen Sie den anderen Wert nicht einmal als Zahl betrachten: Wenn eines der Bits aktiviert ist, ist es nicht gleich Null, und dann müssen Sie nur ein Bit betrachten, um festzustellen, ob es größer oder kleiner als Null ist.
quelle
Wenn dieser Code jedes Mal interpretiert wird, wenn er ausgeführt wird, gibt es einen Unterschied, da das Tokenisieren und Interpretieren im
10000000000000
Vergleich zu länger dauert1000
. Dies ist jedoch die offensichtliche erste Optimierung der Interpreter in diesem Fall: einmal tokenisieren und die Token interpretieren.quelle