Improve Cacheline Efficiency in QuicPacketHeader.

It's compressed to two cachelines. All fields relevant to short headers (i.e. the bulk of packets) are in the first cacheline.

Other code must be reviewed to avoid unnecessary access to long header fields in the short header packet path.

PiperOrigin-RevId: 767810253
diff --git a/quiche/quic/core/quic_packets.cc b/quiche/quic/core/quic_packets.cc
index a8c438c..d127cea 100644
--- a/quiche/quic/core/quic_packets.cc
+++ b/quiche/quic/core/quic_packets.cc
@@ -160,23 +160,23 @@
 
 QuicPacketHeader::QuicPacketHeader()
     : destination_connection_id(EmptyQuicConnectionId()),
+      possible_stateless_reset_token({}),
+      packet_number_length(PACKET_4BYTE_PACKET_NUMBER),
+      form(GOOGLE_QUIC_PACKET),
+      type_byte(0),
       destination_connection_id_included(CONNECTION_ID_PRESENT),
-      source_connection_id(EmptyQuicConnectionId()),
       source_connection_id_included(CONNECTION_ID_ABSENT),
       reset_flag(false),
       version_flag(false),
       has_possible_stateless_reset_token(false),
-      packet_number_length(PACKET_4BYTE_PACKET_NUMBER),
-      type_byte(0),
       version(UnsupportedQuicVersion()),
-      nonce(nullptr),
-      form(GOOGLE_QUIC_PACKET),
-      long_packet_type(INITIAL),
-      possible_stateless_reset_token({}),
-      retry_token_length_length(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0),
+      source_connection_id(EmptyQuicConnectionId()),
+      remaining_packet_length(0),
       retry_token(absl::string_view()),
+      nonce(nullptr),
+      long_packet_type(INITIAL),
       length_length(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0),
-      remaining_packet_length(0) {}
+      retry_token_length_length(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0) {}
 
 QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;
 
diff --git a/quiche/quic/core/quic_packets.h b/quiche/quic/core/quic_packets.h
index 21d20ba..ccac3fe 100644
--- a/quiche/quic/core/quic_packets.h
+++ b/quiche/quic/core/quic_packets.h
@@ -13,20 +13,19 @@
 #include <optional>
 #include <ostream>
 #include <string>
-#include <utility>
 
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/frames/quic_frame.h"
 #include "quiche/quic/core/quic_ack_listener_interface.h"
 #include "quiche/quic/core/quic_bandwidth.h"
 #include "quiche/quic/core/quic_connection_id.h"
-#include "quiche/quic/core/quic_constants.h"
-#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_packet_number.h"
 #include "quiche/quic/core/quic_time.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_versions.h"
-#include "quiche/quic/platform/api/quic_export.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
+#include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/common/quiche_endian.h"
 
 namespace quic {
 
@@ -106,6 +105,11 @@
     QuicByteCount retry_token_length,
     quiche::QuicheVariableLengthIntegerLength length_length);
 
+// This struct is organized so that the first cacheline contains fields relevant
+// to short headers. Thus, for most packets only one line will be loaded into
+// the cache.
+// TODO(martinduke): Scrub the code to eliminate unnecessary access to cold
+// cachelines.
 struct QUICHE_EXPORT QuicPacketHeader {
   QuicPacketHeader();
   QuicPacketHeader(const QuicPacketHeader& other);
@@ -116,12 +120,21 @@
   QUICHE_EXPORT friend std::ostream& operator<<(std::ostream& os,
                                                 const QuicPacketHeader& header);
 
-  // Universal header. All QuicPacket headers will have a connection_id and
-  // public flags.
+  // Universal header. All QuicPacket headers will have a destination
+  // connection_id and type byte. This fits in one cacheline.
   QuicConnectionId destination_connection_id;
+  // Only valid if |has_possible_stateless_reset_token| is true.
+  // Stores last 16 bytes of a this packet, used to check whether this packet is
+  // a stateless reset packet on decryption failure.
+  StatelessResetToken possible_stateless_reset_token;
+  QuicPacketNumber packet_number;
+  QuicPacketNumberLength packet_number_length;
+  // Format of this header.
+  PacketHeaderFormat form;
+  uint8_t type_byte;
   QuicConnectionIdIncluded destination_connection_id_included;
-  QuicConnectionId source_connection_id;
   QuicConnectionIdIncluded source_connection_id_included;
+  // TODO(martinduke): Compress these into bitfields.
   // This is only used for Google QUIC.
   bool reset_flag;
   // For Google QUIC, version flag in packets from the server means version
@@ -130,37 +143,43 @@
   // Indicates whether |possible_stateless_reset_token| contains a valid value
   // parsed from the packet buffer. IETF QUIC only, always false for GQUIC.
   bool has_possible_stateless_reset_token;
-  QuicPacketNumberLength packet_number_length;
-  uint8_t type_byte;
+
+  // There are 8 bytes still available in the first cacheline.  Start with long
+  // header stuff.
+  // TODO(martinduke): Compress ParsedQuicVersion to 1 Byte.
   ParsedQuicVersion version;
-  // nonce contains an optional, 32-byte nonce value. If not included in the
-  // packet, |nonce| will be empty.
-  DiversificationNonce* nonce;
-  QuicPacketNumber packet_number;
-  // Format of this header.
-  PacketHeaderFormat form;
-  // Short packet type is reflected in packet_number_length.
-  QuicLongHeaderType long_packet_type;
-  // Only valid if |has_possible_stateless_reset_token| is true.
-  // Stores last 16 bytes of a this packet, used to check whether this packet is
-  // a stateless reset packet on decryption failure.
-  StatelessResetToken possible_stateless_reset_token;
-  // Length of the retry token length variable length integer field,
-  // carried only by v99 IETF Initial packets.
-  quiche::QuicheVariableLengthIntegerLength retry_token_length_length;
-  // Retry token, carried only by v99 IETF Initial packets.
-  absl::string_view retry_token;
-  // Length of the length variable length integer field,
-  // carried only by v99 IETF Initial, 0-RTT and Handshake packets.
-  quiche::QuicheVariableLengthIntegerLength length_length;
-  // Length of the packet number and payload, carried only by v99 IETF Initial,
+
+  // END FIRST CACHELINE
+
+  QuicConnectionId source_connection_id;
+  // Length of the packet number and payload, carried only by IETF Initial,
   // 0-RTT and Handshake packets. Also includes the length of the
   // diversification nonce in server to client 0-RTT packets.
   QuicByteCount remaining_packet_length;
+  // Retry token, carried only by v99 IETF Initial packets.
+  absl::string_view retry_token;
+  // nonce contains an optional, 32-byte nonce value. If not included in the
+  // packet, |nonce| will be empty.
+  DiversificationNonce* nonce;
+  // Short packet type is reflected in packet_number_length.
+  QuicLongHeaderType long_packet_type;
+  // TODO(martinduke): Compress these into bitfields.
+  // Length of the length variable length integer field,
+  // carried only by v99 IETF Initial, 0-RTT and Handshake packets.
+  quiche::QuicheVariableLengthIntegerLength length_length;
+  // Length of the retry token length variable length integer field,
+  // carried only by v99 IETF Initial packets.
+  quiche::QuicheVariableLengthIntegerLength retry_token_length_length;
+  // 64-bit compilers will add five bytes of padding here.
+  // END SECOND CACHELINE
 
   bool operator==(const QuicPacketHeader& other) const;
   bool operator!=(const QuicPacketHeader& other) const;
 };
+static_assert(offsetof(struct QuicPacketHeader, version) <= 64,
+              "all short header fields must fit in a single cacheline");
+static_assert(sizeof(QuicPacketHeader) <= 128,
+              "QuicPacketHeader is too large.");
 
 struct QUICHE_EXPORT QuicPublicResetPacket {
   QuicPublicResetPacket();
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc
index f1a720d..001e690 100644
--- a/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -571,7 +571,7 @@
       << " ecn_codepoint passed: " << (info.ecn_codepoint == ECN_NOT_ECT)
       << " sizeof(ReceivedPacketInfo) passed: "
       << (sizeof(size_t) != 8 ||
-          sizeof(QuicConnection::ReceivedPacketInfo) == 304);
+          sizeof(QuicConnection::ReceivedPacketInfo) == 288);
   return info.destination_address == QuicSocketAddress() &&
          info.source_address == QuicSocketAddress() &&
          info.receipt_time == QuicTime::Zero() &&
@@ -585,7 +585,7 @@
          // have changed. Please add the relevant conditions and update the
          // length below.
          (sizeof(size_t) != 8 ||
-          sizeof(QuicConnection::ReceivedPacketInfo) == 304);
+          sizeof(QuicConnection::ReceivedPacketInfo) == 288);
 }
 
 // static