diff --git a/homa.h b/homa.h index 9da4ca65..f426c18d 100644 --- a/homa.h +++ b/homa.h @@ -116,7 +116,7 @@ struct homa_args_recv_ipv4 { int type; }; -/* Flag bits for homa_recv (see man page for documentation): +/* Flag bits for homa_recv (see man page for documentation): */ #define HOMA_RECV_REQUEST 0x01 #define HOMA_RECV_RESPONSE 0x02 diff --git a/homa_api.c b/homa_api.c index dcee0824..6071ece7 100644 --- a/homa_api.c +++ b/homa_api.c @@ -43,9 +43,9 @@ * id for the incoming message. * @msglen: If non-null, the total length of the message will be returned * here. - * + * * Return: The number of bytes of data returned at @buf. If an error - * occurred, -1 is returned and errno is set appropriately. + * occurred, -1 is returned and errno is set appropriately. */ ssize_t homa_recv(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, size_t *addrlen, uint64_t *id, @@ -95,9 +95,9 @@ ssize_t homa_recv(int sockfd, void *buf, size_t len, int flags, * id for the incoming message. * @msglen: If non-null, the total length of the message will be returned * here. - * + * * Return: The number of bytes of data returned at @buf. If an error - * occurred, -1 is returned and errno is set appropriately. + * occurred, -1 is returned and errno is set appropriately. */ ssize_t homa_recvv(int sockfd, const struct iovec *iov, int iovcnt, int flags, struct sockaddr *src_addr, size_t *addrlen, uint64_t *id, @@ -136,13 +136,13 @@ ssize_t homa_recvv(int sockfd, const struct iovec *iov, int iovcnt, int flags, * @dest_addr: Address of the RPC's client (returned by homa_recv when * the message was received). * @addrlen: Size of @dest_addr in bytes. - * @id: Unique identifier for the request, as returned by homa_recv + * @id: Unique identifier for the request, as returned by homa_recv * when the request was received. - * + * * @dest_addr and @id must correspond to a previously-received request * for which no reply has yet been sent; if there is no such active request, * then this function does nothing. - * + * * Return: 0 means the response has been accepted for delivery. If an * error occurred, -1 is returned and errno is set appropriately. */ @@ -174,13 +174,13 @@ ssize_t homa_reply(int sockfd, const void *response, size_t resplen, * @dest_addr: Address of the RPC's client (returned by homa_recv when * the message was received). * @addrlen: Size of @dest_addr in bytes. - * @id: Unique identifier for the request, as returned by homa_recv + * @id: Unique identifier for the request, as returned by homa_recv * when the request was received. - * + * * @dest_addr and @id must correspond to a previously-received request * for which no reply has yet been sent; if there is no such active request, * then this function does nothing. - * + * * Return: 0 means the response has been accepted for delivery. If an * error occurred, -1 is returned and errno is set appropriately. */ @@ -211,7 +211,7 @@ ssize_t homa_replyv(int sockfd, const struct iovec *iov, int iovcnt, * @addrlen: Size of @dest_addr in bytes. * @id: A unique identifier for the request will be returned here; * this can be used later to find the response for this request. - * + * * Return: 0 means the request has been accepted for delivery. If an * error occurred, -1 is returned and errno is set appropriately. */ @@ -221,7 +221,7 @@ int homa_send(int sockfd, const void *request, size_t reqlen, { struct homa_args_send_ipv4 args; int result; - + if (dest_addr->sa_family != AF_INET) { errno = EAFNOSUPPORT; return -EAFNOSUPPORT; @@ -248,7 +248,7 @@ int homa_send(int sockfd, const void *request, size_t reqlen, * @addrlen: Size of @dest_addr in bytes. * @id: A unique identifier for the request will be returned here; * this can be used later to find the response for this request. - * + * * Return: 0 means the request has been accepted for delivery. If an * error occurred, -1 is returned and errno is set appropriately. */ @@ -280,7 +280,7 @@ int homa_sendv(int sockfd, const struct iovec *iov, int iovcnt, * @id: Unique identifier for the RPC to abort (return value * from previous call to homa_send). Should be a client * RPC. - * + * * Return: If an error occurred, -1 is returned and errno is set * appropriately. Otherwise zero is returned. */ diff --git a/homa_impl.h b/homa_impl.h index 2380dea1..2649343d 100644 --- a/homa_impl.h +++ b/homa_impl.h @@ -109,7 +109,7 @@ extern void homa_throttle_lock_slow(struct homa *homa); /** * enum homa_packet_type - Defines the possible types of Homa packets. - * + * * See the xxx_header structs below for more information about each type. */ enum homa_packet_type { @@ -182,7 +182,7 @@ enum homa_packet_type { /** define CACHE_LINE_SIZE - The number of bytes in a cache line. */ #define CACHE_LINE_SIZE 64 -/** +/** * define NUM_PEER_UNACKED_IDS - The number of ids for unacked RPCs that * can be stored in a struct homa_peer. */ @@ -200,22 +200,22 @@ struct common_header { * Must be in the same position as in a TCP header. */ __be16 sport; - + /** * @dport: Port on destination that is to receive packet. Must be * in the same position as in a TCP header. */ __be16 dport; - + /** * @unused1: corresponds to the sequence number field in TCP headers; * must not be used by Homa, in case it gets incremented during TCP * offload. */ __be32 unused1; - + __be32 unused2; - + /** * @doff: High order 4 bits holds the number of 4-byte chunks in a * data_header (low-order bits unused). Used only for DATA packets; @@ -225,16 +225,16 @@ struct common_header { /** @type: One of the values of &enum packet_type. */ __u8 type; - + __u16 unused3; - + /** * @checksum: not used by Homa, but must occupy the same bytes as * the checksum in a TCP header (TSO may modify this?).*/ __be16 checksum; - + __u16 unused4; - + /** * @sender_id: the identifier of this RPC as used on the sender (i.e., * if the low-order bit is set, then the sender is the server for @@ -254,20 +254,20 @@ struct common_header { * return an explicit ACK. */ struct homa_ack { - /** + /** * @id: The client's identifier for the RPC. 0 means this ack * is invalid. */ __be64 client_id; - + /** @client_port: The client-side port for the RPC. */ __be16 client_port; - + /** @server_port: The server-side port for the RPC. */ __be16 server_port; } __attribute__((packed)); -/** +/** * struct data_segment - Wire format for a chunk of data that is part of * a DATA packet. A single sk_buff can hold multiple data_segments in order * to enable send and receive offload (the idea is to carry many network @@ -282,15 +282,15 @@ struct data_segment { * to be in order. */ __be32 offset; - + /** @segment_length: Number of bytes of data in this segment. */ __be32 segment_length; - + /** @ack: If the @client_id field is nonzero, provides info about * an RPC that the recipient can now safely free. */ struct homa_ack ack; - + /** @data: the payload of this segment. */ char data[0]; } __attribute__((packed)); @@ -300,10 +300,10 @@ struct data_segment { */ struct data_header { struct common_header common; - + /** @message_length: Total #bytes in the *message* */ __be32 message_length; - + /** * @incoming: The receiver can expect the sender to send all of the * bytes in the message up to at least this offset (exclusive), @@ -312,7 +312,7 @@ struct data_header { * transmits unilaterally (e.g., to send batches, such as with GSO). */ __be32 incoming; - + /** * @cutoff_version: The cutoff_version from the most recent * CUTOFFS packet that the source of this packet has received @@ -326,9 +326,9 @@ struct data_header { * (it has already been sent previously). */ __u8 retransmit; - + __u8 pad; - + /** @seg: First of possibly many segments */ struct data_segment seg; } __attribute__((packed)); @@ -351,15 +351,15 @@ _Static_assert(((sizeof(struct data_header) - sizeof(struct data_segment)) struct grant_header { /** @common: Fields common to all packet types. */ struct common_header common; - + /** * @offset: Byte offset within the message. - * + * * The sender should now transmit all data up to (but not including) * this offset ASAP, if it hasn't already. */ __be32 offset; - + /** * @priority: The sender should use this priority level for all future * MESSAGE_FRAG packets for this message, until a GRANT is received @@ -382,13 +382,13 @@ _Static_assert(sizeof(struct grant_header) <= HOMA_MAX_HEADER, struct resend_header { /** @common: Fields common to all packet types. */ struct common_header common; - + /** * @offset: Offset within the message of the first byte of data that * should be retransmitted. */ __be32 offset; - + /** * @length: Number of bytes of data to retransmit; this could specify * a range longer than the total message size. Zero is a special case @@ -397,10 +397,10 @@ struct resend_header { * response if the client no longer cares about this RPC. */ __be32 length; - + /** * @priority: Packet priority to use. - * + * * The sender should transmit all the requested data using this * priority. */ @@ -429,7 +429,7 @@ _Static_assert(sizeof(struct unknown_header) <= HOMA_MAX_HEADER, /** * struct busy_header - Wire format for BUSY packets. - * + * * These packets tell the recipient that the sender is still alive (even if * it isn't sending data expected by the recipient). */ @@ -443,21 +443,21 @@ _Static_assert(sizeof(struct busy_header) <= HOMA_MAX_HEADER, /** * struct cutoffs_header - Wire format for CUTOFFS packets. - * + * * These packets tell the recipient how to assign priorities to * unscheduled packets. */ struct cutoffs_header { /** @common: Fields common to all packet types. */ struct common_header common; - + /** * @unsched_cutoffs: priorities to use for unscheduled packets * sent to the sender of this packet. See documentation for * @homa.unsched_cutoffs for the meanings of these values. */ __be32 unsched_cutoffs[HOMA_MAX_PRIORITIES]; - + /** * @cutoff_version: unique identifier associated with @unsched_cutoffs. * Must be included in future DATA packets sent to the sender of @@ -471,7 +471,7 @@ _Static_assert(sizeof(struct cutoffs_header) <= HOMA_MAX_HEADER, /** * struct freeze_header - Wire format for FREEZE packets. - * + * * These packets tell the recipient to freeze its timetrace; used * for debugging. */ @@ -485,7 +485,7 @@ _Static_assert(sizeof(struct freeze_header) <= HOMA_MAX_HEADER, /** * struct need_ack_header - Wire format for NEED_ACK packets. - * + * * These packets ask the recipient (a client) to return an ACK message if * the packet's RPC is no longer active. */ @@ -499,7 +499,7 @@ _Static_assert(sizeof(struct need_ack_header) <= HOMA_MAX_HEADER, /** * struct ack_header - Wire format for ACK packets. - * + * * These packets are sent from a client to a server to indicate that * a set of RPCs is no longer active on the client, so the server can * free any state it may have for them. @@ -507,10 +507,10 @@ _Static_assert(sizeof(struct need_ack_header) <= HOMA_MAX_HEADER, struct ack_header { /** @common: Fields common to all packet types. */ struct common_header common; - + /** @num_acks: number of (leading) elements in @acks that are valid. */ __be16 num_acks; - + struct homa_ack acks[NUM_PEER_UNACKED_IDS]; } __attribute__((packed)); _Static_assert(sizeof(struct ack_header) <= HOMA_MAX_HEADER, @@ -526,7 +526,7 @@ struct homa_message_out { * less than 0 means this structure is uninitialized and therefore * not in use.*/ int length; - + /** * @packets: singly-linked list of all packets in message, linked * using homa_next_skb. The list is in order of offset in the message @@ -534,38 +534,38 @@ struct homa_message_out { * data_segments, which will be split into separate packets by GSO. */ struct sk_buff *packets; - + /** * @num_skbs: Total number of buffers in @packets. Will be 0 if * @length is less than 0. */ int num_skbs; - + /** * @next_packet: Pointer within @request of the next packet to transmit. - * + * * All packets before this one have already been sent. NULL means * entire message has been sent. */ struct sk_buff *next_packet; - + /** * @unscheduled: Initial bytes of message that we'll send * without waiting for grants. May be larger than @length; */ int unscheduled; - - /** + + /** * @granted: Total number of bytes we are currently permitted to * send, including unscheduled bytes; must wait for grants before * sending bytes at or beyond this position. Never larger than * @length. */ int granted; - + /** @priority: Priority level to use for future scheduled packets. */ __u8 sched_priority; - + /** * @init_cycles: Time in get_cycles units when this structure was * initialized. Used to find the oldest outgoing message. @@ -575,7 +575,7 @@ struct homa_message_out { /** * struct homa_message_in - Holds the state of a message received by - * this machine; used for both requests and responses. + * this machine; used for both requests and responses. */ struct homa_message_in { /** @@ -584,7 +584,7 @@ struct homa_message_in { * not in use. */ int total_length; - + /** * @packets: DATA packets received for this message so far. The list * is sorted in order of offset (head is lowest offset), but @@ -593,13 +593,13 @@ struct homa_message_in { * exactly one data_segment. */ struct sk_buff_head packets; - + /** * @num_skbs: Total number of buffers in @packets. Will be 0 if * @total_length is less than 0. */ int num_skbs; - + /** * @bytes_remaining: Amount of data for this message that has * not yet been received; will determine the message's priority. @@ -615,16 +615,16 @@ struct homa_message_in { * @homa->grantable_lock. */ int incoming; - + /** @priority: Priority level to include in future GRANTS. */ int priority; - + /** * @scheduled: True means some of the bytes of this message * must be scheduled with grants. */ bool scheduled; - + /** * @possibly_in_grant_queue: True means this RPC may be linked * into peer->grantable_rpcs. Zero means it can't possibly be in @@ -632,13 +632,13 @@ struct homa_message_in { * lock) when cleaning up the RPC. */ bool possibly_in_grant_queue; - + /** * The offset within the message of the next byte to be copied * out of the message to a user buffer. */ int xfer_offset; - + /** * The next buffer in @packets to consider when copying data out of * the message to a user buffer (all skbs before this one have @@ -646,7 +646,7 @@ struct homa_message_in { * any data. */ struct sk_buff *xfer_skb; - + /** * @birth: get_cycles time when this RPC was added to the grantable * list. Invalid if RPC isn't in the grantable list. @@ -665,7 +665,7 @@ struct homa_interest { * woken up when a suitable message becomes available. */ struct task_struct *thread; - + /** * @rpc: If non-null, it identifies the RPC given by @id and * @peer_addr, and that RPC is locked. Only set by @@ -673,7 +673,7 @@ struct homa_interest { * homa_wait_for_message doesn't need to relock the RPC. */ struct homa_rpc *ready_rpc; - + /** * @id: Id of the RPC that was found, or zero if none. This variable * is used for synchronization, and must be set after the variables @@ -683,32 +683,32 @@ struct homa_interest { * deleted. */ atomic_long_t id; - + /** * @peer_addr: IP address of the peer for the matching RPC. Valid * only if @id is nonzero. */ __be32 peer_addr; - + /** * @peer_port: Port of the peer for the matching RPC. Valid * only if @id is nonzero. */ __u16 peer_port; - + /** * @reg_rpc: RPC whose @interest field points here, or * NULL if none. */ struct homa_rpc *reg_rpc; - + /** * @request_links: For linking this object into * &homa_sock.request_interests. The interest must not be linked * on either this list or @response_links if @id is nonzero. */ struct list_head request_links; - + /** * @response_links: For linking this object into * &homa_sock.request_interests. @@ -739,16 +739,16 @@ static void inline homa_interest_init(struct homa_interest *interest) struct homa_rpc { /** @hsk: Socket that owns the RPC. */ struct homa_sock *hsk; - + /** @lock: Used to synchronize modifications to this structure; * points to the lock in hsk->client_rpc_buckets or * hsk->server_rpc_buckets. */ struct spinlock *lock; - + /** * @state: The current state of this RPC: - * + * * @RPC_OUTGOING: The RPC is waiting for @msgout to be transmitted * to the peer. * @RPC_INCOMING: The RPC is waiting for data @msgin to be received @@ -763,10 +763,10 @@ struct homa_rpc { * @RPC_DEAD: RPC has been deleted and is waiting to be * reaped. In some cases, information in the RPC * structure may be accessed in this state. - * + * * Client RPCs pass through states in the following order: * RPC_OUTGOING, RPC_INCOMING, RPC_READY, RPC_DEAD. - * + * * Server RPCs pass through states in the following order: * RPC_INCOMING, RPC_READY, RPC_IN_SERVICE, RPC_OUTGOING, RPC_DEAD. */ @@ -777,13 +777,13 @@ struct homa_rpc { RPC_IN_SERVICE = 8, RPC_DEAD = 9 } state; - - /** + + /** * @dont_reap: True means data is still being copied out of the * RPC to a receiver, so it isn't safe to reap it yet. */ bool dont_reap; - + /** * @grants_in_progress: Count of active grant sends for this RPC; * it's not safe to reap the RPC unless this value is zero. @@ -791,100 +791,100 @@ struct homa_rpc { * while sending grants, to reduce contention. */ atomic_t grants_in_progress; - + /** * @peer: Information about the other machine (the server, if * this is a client RPC, or the client, if this is a server RPC). */ struct homa_peer *peer; - + /** @dport: Port number on @peer that will handle packets. */ __u16 dport; - + /** * @id: Unique identifier for the RPC among all those issued * from its port. The low-order bit indicates whether we are * server (1) or client (0) for this RPC. */ __u64 id; - + /** * @error: Only used on clients. If nonzero, then the RPC has * failed and the value is a negative errno that describes the * problem. */ int error; - + /** * @msgin: Information about the message we receive for this RPC * (for server RPCs this is the request, for client RPCs this is the * response). */ struct homa_message_in msgin; - - /** + + /** * @msgout: Information about the message we send for this RPC * (for client RPCs this is the request, for server RPCs this is the * response). */ struct homa_message_out msgout; - + /** * @hash_links: Used to link this object into a hash bucket for * either @hsk->client_rpc_buckets (for a client RPC), or * @hsk->server_rpc_buckets (for a server RPC). */ struct hlist_node hash_links; - + /** * @active_links: For linking this object into @hsk->active_rpcs. * The next field will be LIST_POISON1 if this RPC hasn't yet been * linked into @hsk->active_rpcs. Access with RCU. */ struct list_head active_links; - + /** @dead_links: For linking this object into @hsk->dead_rpcs. */ struct list_head dead_links; - + /** * @interest: Describes a thread that wants to be notified when * msgin is complete, or NULL if none. */ struct homa_interest *interest; - + /** * @ready_links: Used to link this object into * &homa_sock.ready_requests or &homa_sock.ready_responses. */ struct list_head ready_links; - + /** * @grantable_links: Used to link this RPC into peer->grantable_rpcs. * If this RPC isn't in peer->grantable_rpcs, this is an empty * list pointing to itself. */ struct list_head grantable_links; - + /** * @throttled_links: Used to link this RPC into homa->throttled_rpcs. * If this RPC isn't in homa->throttled_rpcs, this is an empty * list pointing to itself. */ struct list_head throttled_links; - + /** * @silent_ticks: Number of times homa_timer has been invoked * since the last time a packet indicating progress was received * for this RPC, so we don't need to send a resend for a while. */ int silent_ticks; - + /** * @resend_timer_ticks: Value of homa->timer_ticks the last time * we sent a RESEND for this RPC. */ __u32 resend_timer_ticks; - + /** * @done_timer_ticks: The value of homa->timer_ticks the first * time we noticed that this (server) RPC is done (all response @@ -966,7 +966,7 @@ struct homa_socktab { * synchronize port allocation. */ struct mutex write_lock; - + /** * @buckets: Heads of chains for hash table buckets. Chains * consist of homa_socktab_link objects. @@ -992,14 +992,14 @@ struct homa_socktab_links { struct homa_socktab_scan { /** @socktab: The table that is being scanned. */ struct homa_socktab *socktab; - + /** * @current_bucket: the index of the bucket in socktab->buckets * currently being scanned. If >= HOMA_SOCKTAB_BUCKETS, the scan * is complete. */ int current_bucket; - + /** * @next: the next socket to return from homa_socktab_next (this * socket has not yet been returned). NULL means there are no @@ -1029,7 +1029,7 @@ struct homa_rpc_bucket { * deletion and garbage collection of RPCs. */ struct spinlock lock; - + /** @rpcs: list of RPCs that hash to this bucket. */ struct hlist_head rpcs; }; @@ -1040,7 +1040,7 @@ struct homa_rpc_bucket { struct homa_sock { /** @inet: Generic socket data; must be the first field. */ struct inet_sock inet; - + /** * @lock: Must be held when modifying fields such as interests * and lists of RPCs. This lock is used in place of sk->sk_lock @@ -1049,40 +1049,40 @@ struct homa_sock { * strategy. */ struct spinlock lock; - + /** * @last_locker: identifies the code that most recently acquired * @lock successfully. Occasionally used for debugging. */ char *last_locker; - + /** * @protect_count: counts the number of calls to homa_protect_rpcs * for which there have not yet been calls to homa_unprotect_rpcs. * See sync.txt for more info. */ atomic_t protect_count; - + /** * @homa: Overall state about the Homa implementation. NULL * means this socket has been deleted. */ struct homa *homa; - + /** @shutdown: True means the socket is no longer usable. */ bool shutdown; - + /** * Port number: identifies this socket uniquely among all * those on this node. */ __u16 port; - + /** * @client_socktab_links: Links this socket into the homa_socktab * based on @port. */ struct homa_socktab_links socktab_links; - + /** * @active_rpcs: List of all existing RPCs related to this socket, * including both client and server RPCs. This list isn't strictly @@ -1093,47 +1093,47 @@ struct homa_sock { * RCU so timer can access without locking. */ struct list_head active_rpcs; - + /** * @dead_rpcs: Contains RPCs for which homa_rpc_free has been * called, but their packet buffers haven't yet been freed. */ struct list_head dead_rpcs; - + /** @dead_skbs: Total number of socket buffers in RPCs on dead_rpcs. */ int dead_skbs; - + /** * @ready_requests: Contains server RPCs in RPC_READY state that * have not yet been claimed. The head is oldest, i.e. next to return. */ struct list_head ready_requests; - + /** * @ready_responses: Contains client RPCs in RPC_READY state that * have not yet been claimed. The head is oldest, i.e. next to return. */ struct list_head ready_responses; - + /** * @request_interests: List of threads that want to receive incoming * request messages. */ struct list_head request_interests; - + /** * @response_interests: List of threads that want to receive incoming * response messages. */ struct list_head response_interests; - + /** * @client_rpc_buckets: Hash table for fast lookup of client RPCs. * Modifications are synchronized with bucket locks, not * the socket lock. */ struct homa_rpc_bucket client_rpc_buckets[HOMA_CLIENT_RPC_BUCKETS]; - + /** * @server_rpc_buckets: Hash table for fast lookup of server RPCs. * Modifications are synchronized with bucket locks, not @@ -1151,13 +1151,13 @@ struct homa_sock { struct homa_dead_dst { /** @dst: Entry that is no longer used by a struct homa_peer. */ struct dst_entry *dst; - + /** * @gc_time: Time (in units of get_cycles) when it is safe * to free @dst. */ __u64 gc_time; - + /** @dst_links: Used to link together entries in peertab->dead_dsts. */ struct list_head dst_links; }; @@ -1188,13 +1188,13 @@ struct homa_peertab { * for lookups (RCU is used instead). */ struct spinlock write_lock; - + /** * @dead_dsts: List of dst_entries that are waiting to be deleted. * Hold @write_lock when manipulating. */ struct list_head dead_dsts; - + /** * @buckets: Pointer to heads of chains of homa_peers for each bucket. * Malloc-ed, and must eventually be freed. NULL means this structure @@ -1205,21 +1205,21 @@ struct homa_peertab { /** * struct homa_peer - One of these objects exists for each machine that we - * have communicated with (either as client or server). + * have communicated with (either as client or server). */ struct homa_peer { /** @daddr: IPV4 address for the machine. */ __be32 addr; - + /** @flow: Addressing info needed to send packets. */ struct flowi flow; - + /** * @dst: Used to route packets to this peer; we own a reference * to this, which we must eventually release. */ struct dst_entry *dst; - + /** * @unsched_cutoffs: priorities to use for unscheduled packets * sent to this host, as specified in the most recent CUTOFFS @@ -1227,7 +1227,7 @@ struct homa_peer { * for the meanings of these values. */ int unsched_cutoffs[HOMA_MAX_PRIORITIES]; - + /** * @cutoff_version: value of cutoff_version in the most recent * CUTOFFS packet received from this peer. 0 means we haven't @@ -1235,13 +1235,13 @@ struct homa_peer { * stored in network byte order. */ __be16 cutoff_version; - + /** * last_update_jiffies: time in jiffies when we sent the most * recent CUTOFFS packet to this peer. */ unsigned long last_update_jiffies; - + /** * grantable_rpcs: Contains all homa_rpcs (both requests and * responses) involving this peer whose msgins require (or required @@ -1250,72 +1250,72 @@ struct homa_peer { * Locked with homa->grantable_lock. */ struct list_head grantable_rpcs; - + /** * @grantable_links: Used to link this peer into homa->grantable_peers, * if there are entries in grantable_rpcs. If grantable_rpcs is empty, * this is an empty list pointing to itself. */ struct list_head grantable_links; - + /** * @peertab_links: Links this object into a bucket of its * homa_peertab. */ struct hlist_node peertab_links; - + /** * @outstanding_resends: the number of resend requests we have * sent to this server (spaced @homa.resend_interval apart) since * we received a packet from this peer. */ int outstanding_resends; - + /** * @most_recent_resend: @homa->timer_ticks when the most recent * resend was sent to this peer. */ int most_recent_resend; - + /** * @least_recent_rpc: of all the RPCs for this peer scanned at * @current_ticks, this is the RPC whose @resend_timer_ticks * is farthest in the past. */ struct homa_rpc *least_recent_rpc; - + /** * @least_recent_ticks: the @resend_timer_ticks value for * @least_recent_rpc. */ __u32 least_recent_ticks; - + /** * @current_ticks: the value of @homa->timer_ticks the last time * that @least_recent_rpc and @least_recent_ticks were computed. * Used to detect the start of a new homa_timer pass. */ __u32 current_ticks; - + /** * @resend_rpc: the value of @least_recent_rpc computed in the * previous homa_timer pass. This RPC will be issued a RESEND * in the current pass, if it still needs one. */ struct homa_rpc *resend_rpc; - + /** * @num_acks: the number of (initial) entries in @acks that * currently hold valid information. */ int num_acks; - + /** * @acks: info about client RPCs whose results have been completely * received. */ struct homa_ack acks[NUM_PEER_UNACKED_IDS]; - + /** * @ack_lock: used to synchronize access to @num_acks and @acks. */ @@ -1336,7 +1336,7 @@ enum homa_freeze_type { /** * struct homa - Overall information about the Homa protocol implementation. - * + * * There will typically only exist one of these at a time, except during * unit tests. */ @@ -1347,17 +1347,17 @@ struct homa { * Accessed without locks. */ atomic64_t next_outgoing_id; - + /** * @link_idle_time: The time, measured by get_cycles() at which we * estimate that all of the packets we have passed to Linux for * transmission will have been transmitted. May be in the past. * This estimate assumes that only Homa is transmitting data, so - * it could be a severe underestimate if there is competing traffic + * it could be a severe underestimate if there is competing traffic * from, say, TCP. Access only with atomic ops. */ atomic64_t link_idle_time __attribute__((aligned(CACHE_LINE_SIZE))); - + /** * @grantable_lock: Used to synchronize access to @grantable_peers and * @num_grantable_peers. @@ -1371,16 +1371,16 @@ struct homa { * first one on the first peer's list). */ struct list_head grantable_peers; - + /** @num_grantable_peers: The number of peers in grantable_peers. */ int num_grantable_peers; - + /** * @grant_nonfifo: How many bytes should be granted using the * normal priority system between grants to the oldest message. */ int grant_nonfifo; - + /** * @grant_nonfifo_left: Counts down bytes using the normal * priority mechanism. When this reaches zero, it's time to grant @@ -1393,27 +1393,27 @@ struct homa { * runs at a time. Only used in "try" mode: never block on this. */ struct spinlock pacer_mutex __attribute__((aligned(CACHE_LINE_SIZE))); - + /** * @pacer_fifo_fraction: The fraction of time (in thousandths) when * the pacer should transmit next from the oldest message, rather * than the highest-priority message. Set externally via sysctl. */ int pacer_fifo_fraction; - + /** * @pacer_fifo_count: When this becomes <= zero, it's time for the * pacer to allow the oldest RPC to transmit. */ int pacer_fifo_count; - + /** * @throttle_lock: Used to synchronize access to @throttled_rpcs. To * insert or remove an RPC from throttled_rpcs, must first acquire * the RPC's socket lock, then this lock. */ struct spinlock throttle_lock; - + /** * @throttled_rpcs: Contains all homa_rpcs that have bytes ready * for transmission, but which couldn't be sent without exceeding @@ -1421,13 +1421,13 @@ struct homa { * functions. */ struct list_head throttled_rpcs; - + /** * @throttle_add: The get_cycles() time when the most recent RPC * was added to @throttled_rpcs. */ __u64 throttle_add; - + /** * @throttle_min_bytes: If a packet has fewer bytes than this, then it * bypasses the throttle mechanism and is transmitted immediately. @@ -1439,7 +1439,7 @@ struct homa { * via sysctl. */ int throttle_min_bytes; - + /** * @total_incoming: the total number of bytes that we expect to receive * (across all messages) even if we don't send out any more grants @@ -1449,7 +1449,7 @@ struct homa { * homa_send_grants for why we have to allow this possibility). */ atomic_t total_incoming __attribute__((aligned(CACHE_LINE_SIZE))); - + /** * @next_client_port: A client port number to consider for the * next Homa socket; increments monotonically. Current value may @@ -1457,18 +1457,18 @@ struct homa { * This port may also be in use already; must check. */ __u16 next_client_port __attribute__((aligned(CACHE_LINE_SIZE))); - + /** * @port_map: Information about all open sockets. */ struct homa_socktab port_map __attribute__((aligned(CACHE_LINE_SIZE))); - + /** * @peertab: Info about all the other hosts we have communicated * with; indexed by host IPV4 address. */ struct homa_peertab peers; - + /** * @rtt_bytes: An estimate of the amount of data that can be transmitted * over the wire in the time it takes to send a full-size data packet @@ -1476,54 +1476,54 @@ struct homa { * uplink bandwidth. Set externally via sysctl. */ int rtt_bytes; - + /** * @max_grant_window: if nonzero, determines the maximum number * of granted-but-not-yet-received bytes for a message (may be * greater than rtt_bytes). This feature is currently for * experimentation only. Set externally via sysctl.*/ int max_grant_window; - + /** * @link_bandwidth: The raw bandwidth of the network uplink, in * units of 1e06 bits per second. Set externally via sysctl. */ int link_mbps; - + /** * @poll_usecs: Amount of time (in microseconds) that a thread * will spend busy-waiting for an incoming messages before * going to sleep. Set externally via sysctl. */ int poll_usecs; - + /** * @poll_cycles: The value of @poll_usecs in the units returned * by get_cycles(). */ int poll_cycles; - + /** * @num_priorities: The total number of priority levels available for * Homa's use. Internally, Homa will use priorities from 0 to * num_priorities-1, inclusive. Set externally via sysctl. */ int num_priorities; - + /** * @priority_map: entry i gives the value to store in the high-order * 3 bits of the DSCP field of IP headers to implement priority level * i. Set externally via sysctl. */ int priority_map[HOMA_MAX_PRIORITIES]; - + /** * @max_sched_prio: The highest priority level currently available for * scheduled packets. Levels above this are reserved for unscheduled * packets. Set externally via sysctl. */ int max_sched_prio; - + /** * @unsched_cutoffs: the current priority assignments for incoming * unscheduled packets. The value of entry i is the largest @@ -1535,7 +1535,7 @@ struct homa { * Set externally via sysctl. */ int unsched_cutoffs[HOMA_MAX_PRIORITIES]; - + /** * @cutoff_version: increments every time unsched_cutoffs is * modified. Used to determine when we need to send updates to @@ -1545,21 +1545,21 @@ struct homa { * next version change. Can be set externally via sysctl. */ int cutoff_version; - + /** * @fifo_grant_increment: how many additional bytes to grant in * a "pity" grant sent to the oldest outstanding message. Set * externally via sysctl. */ int fifo_grant_increment; - + /** * @grant_fifo_fraction: The fraction (in thousandths) of granted * bytes that should go to the *oldest* incoming message, rather * than the highest priority ones. Set externally via sysctl. */ int grant_fifo_fraction; - + /** * @duty_cycle: Sets a limit on the fraction of network bandwidth that * may be consumed by a single RPC in units of one-thousandth (1000 @@ -1578,51 +1578,51 @@ struct homa { * from @rtt_bytes and @duty_cycle. */ int grant_threshold; - + /** * @max_overcommit: The maximum number of messages to which Homa will * send grants at any given point in time. Set externally via sysctl. */ int max_overcommit; - + /** * @max_incoming: This value is computed from max_overcommit, and * is the limit on how many bytes are currently permitted to be * granted but not yet received, cumulative across all messages. */ int max_incoming; - + /** * @resend_ticks: When an RPC's @silent_ticks reaches this value, * start sending RESEND requests. */ int resend_ticks; - + /** * @resend_interval: minimum number of homa timer ticks between * RESENDs to the same peer. */ int resend_interval; - + /** * @timeout_resends: Assume that a server is dead if it has not * responded after this many RESENDs have been sent to it. */ int timeout_resends; - + /** * @request_ack_ticks: How many timer ticks we'll wait for the * client to ack an RPC before explicitly requesting an ack. * Set externally via sysctl. */ int request_ack_ticks; - + /** * @reap_limit: Maximum number of packet buffers to free in a * single call to home_rpc_reap. */ int reap_limit; - + /** * @dead_buffs_limit: If the number of packet buffers in dead but * not yet reaped RPCs is less than this number, then Homa reaps @@ -1632,7 +1632,7 @@ struct homa { * to reaping RPCs. Set externally via sysctl. */ int dead_buffs_limit; - + /** * @max_dead_buffs: The largest aggregate number of packet buffers * in dead (but not yet reaped) RPCs that has existed so far in a @@ -1640,33 +1640,33 @@ struct homa { * to begin recalculating. */ int max_dead_buffs; - + /** * @pacer_kthread: Kernel thread that transmits packets from * throttled_rpcs in a way that limits queue buildup in the * NIC. */ struct task_struct *pacer_kthread; - + /** * @pacer_exit: true means that the pacer thread should exit as * soon as possible. */ bool pacer_exit; - + /** * @max_nic_queue_ns: Limits the NIC queue length: we won't queue * up a packet for transmission if link_idle_time is this many * nanoseconds in the future (or more). Set externally via sysctl. */ int max_nic_queue_ns; - + /** * @max_nic_queue_cycles: Same as max_nic_queue_ns, except in units * of get_cycles(). */ int max_nic_queue_cycles; - + /** * @cycles_per_kbyte: the number of cycles, as measured by get_cycles(), * that it takes to transmit 1000 bytes on our uplink. This is actually @@ -1674,26 +1674,26 @@ struct homa { * underestimate NIC queue length and queue too many packets. */ __u32 cycles_per_kbyte; - + /** * @verbose: Nonzero enables additional logging. Set externally via * sysctl. */ int verbose; - + /** * @max_gso_size: Maximum number of bytes that will be included * in a single output packet that Homa passes to Linux. Can be set - * externally via sysctl to lower the limit already enforced by Linux. + * externally via sysctl to lower the limit already enforced by Linux. */ int max_gso_size; - + /** * @max_gro_skbs: Maximum number of socket buffers that can be * aggregated by the GRO mechanism. Set externally via sysctl. */ int max_gro_skbs; - + /** * @gro_policy: An OR'ed together collection of bits that determine * how Homa packets should be steered for SoftIRQ handling. A value @@ -1702,7 +1702,7 @@ struct homa { * it is almost certainly a bad idea; see below). */ int gro_policy; - + /* Bits that can be specified for gro_policy. These were created for * testing, in order to evaluate various possible policies; you almost * certainly should not use any value other than HOMA_GRO_NORMAL. @@ -1723,7 +1723,7 @@ struct homa { * hot spots). Set externally via sysctl. */ int gro_busy_usecs; - + /** * @gro_busy_cycles: Same as gro_busy_usecs, except in units * of get_cycles(). @@ -1752,38 +1752,38 @@ struct homa { /** @metrics_capacity: number of bytes available at metrics. */ size_t metrics_capacity; - + /** * @metrics_length: current length of the string in metrics, * not including terminating NULL character. */ size_t metrics_length; - + /** * @metrics_active_opens: number of open struct files that * currently exist for the metrics file in /proc. */ int metrics_active_opens; - + /** * @flags: a collection of bits that can be set using sysctl * to trigger various behaviors. */ int flags; - + /** * @freeze_type: determines conditions under which the time trace * should be frozen. Set externally via sysctl. */ enum homa_freeze_type freeze_type; - + /** * @sync_freeze: nonzero means that on completion of the next * client RPC we should freeze our timetrace and also the peer's. * Then clear this back to zero again. */ int sync_freeze; - + /** * @temp: the values in this array can be read and written with sysctl. * They have no officially defined purpose, and are available for @@ -1801,19 +1801,19 @@ struct homa { * could move from one CPU to another in the middle of updating a counter), * but this is unlikely, and we can tolerate the occasional miscounts * that might result. - * + * * All counters are free-running: they never reset. */ #define HOMA_NUM_SMALL_COUNTS 64 #define HOMA_NUM_MEDIUM_COUNTS 128 -struct homa_metrics { +struct homa_metrics { /** * @small_msg_bytes: entry i holds the total number of bytes * received in messages whose length is between 64*i and 64*i + 63, * inclusive. */ __u64 small_msg_bytes[HOMA_NUM_SMALL_COUNTS]; - + /** * @medium_msg_bytes: entry i holds the total number of bytes * received in messages whose length is between 1024*i and @@ -1821,162 +1821,162 @@ struct homa_metrics { * (small_msg_counts covers this range). */ __u64 medium_msg_bytes[HOMA_NUM_MEDIUM_COUNTS]; - + /** * @large_msg_count: the total number of messages received whose * length is too large to appear in medium_msg_bytes. */ __u64 large_msg_count; - + /** * @large_msg_bytes: the total number of bytes received in * messages too large to be counted by medium_msg_bytes. */ __u64 large_msg_bytes; - + /** * @sent_msg_bytes: The total number of bytes in outbound * messages. */ __u64 sent_msg_bytes; - + /** * @packets_sent: total number of packets sent for each packet type * (entry 0 corresponds to DATA, and so on). */ __u64 packets_sent[BOGUS-DATA]; - + /** * @packets_received: total number of packets received for each * packet type (entry 0 corresponds to DATA, and so on). */ __u64 packets_received[BOGUS-DATA]; - + /** @priority_bytes: total bytes sent at each priority level. */ __u64 priority_bytes[HOMA_MAX_PRIORITIES]; - + /** @priority_packets: total packets sent at each priority level. */ __u64 priority_packets[HOMA_MAX_PRIORITIES]; - + /** * @requests_received: total number of request messages received. */ __u64 requests_received; - + /** * @requests_queued: total number of requests that were added to * @homa->ready_requests (no thread was waiting). */ __u64 requests_queued; - + /** * @responses_received: total number of response messages received. */ __u64 responses_received; - + /** * @responses_queued: total number of responses that were added to * @homa->ready_responses (no thread was waiting). */ __u64 responses_queued; - + /** * @fast_wakeups: total number of times that a message arrived for * a receiving thread that was polling in homa_wait_for_message. */ __u64 fast_wakeups; - + /** * @slow_wakeups: total number of times that a receiving thread * had to be put to sleep (no message arrived while it was polling). */ __u64 slow_wakeups; - + /** * @poll_cycles: total time spent in the polling loop in * homa_wait_for_message, as measured with get_cycles(). */ __u64 poll_cycles; - + /** * @softirq_calls: total number of calls to homa_softirq (i.e., * total number of GRO packets processed, each of which could contain * multiple Homa packets. */ __u64 softirq_calls; - + /** * @softirq_cycles: total time spent executing homa_softirq, as * measured with get_cycles(). */ __u64 softirq_cycles; - + /** * @linux_softirq_cycles: total time spent executing all softirq * activities, as measured by the linux softirq module, in get_cycles() * units. Only available with modified Linux kernels. */ __u64 linux_softirq_cycles; - + /** * @napi_cycles: total time spent executing all NAPI activities, * as measured by the linux softirq module, in get_cycles() units. * Only available with modified Linux kernels. */ __u64 napi_cycles; - + /** * @send_cycles: total time spent executing the homa_ioc_send * kernel call handler, as measured with get_cycles(). */ __u64 send_cycles; - + /** @send_calls: total number of invocations of the send kernel call. */ __u64 send_calls; - + /** * @recv_cycles: total time spent executing the homa_ioc_recv * kernel call handler (including time when the thread is blocked), * as measured with get_cycles(). */ __u64 recv_cycles; - + /** @recv_calls: total number of invocations of the recv kernel call. */ __u64 recv_calls; - + /** * @blocked_cycles: total time threads spend in blocked state * while executing the homa_ioc_recv kernel call handler. */ __u64 blocked_cycles; - + /** * @reply_cycles: total time spent executing the homa_ioc_reply * kernel call handler, as measured with get_cycles(). */ __u64 reply_cycles; - + /** @reply_calls: total number of invocations of the reply kernel call. */ __u64 reply_calls; - + /** * @abort_cycles: total time spent executing the homa_ioc_abort * kernel call handler, as measured with get_cycles(). */ __u64 abort_cycles; - + /** * @abort_calls: total number of invocations of the homa_ioc_abort * kernel call. */ __u64 abort_calls; - + /** * @grant_cycles: total time spent in homa_send_grants, as measured * with get_cycles(). */ __u64 grant_cycles; - + /** * @user_cycles: total time spent in user threads between the * completion of one Homa system call and the initiation of another. @@ -1987,20 +1987,20 @@ struct homa_metrics { * conditions. */ __u64 user_cycles; - + /** * @timer_cycles: total time spent in homa_timer, as measured with * get_cycles(). */ __u64 timer_cycles; - + /** * @timer_reap_cycles: total time spent by homa_timer to reap dead * RPCs, as measured with get_cycles(). This time is included in * @timer_cycles. */ __u64 timer_reap_cycles; - + /** * @data_pkt_reap_cycles: total time spent by homa_data_pkt to reap * dead RPCs, as measured with get_cycles(). @@ -2012,7 +2012,7 @@ struct homa_metrics { * (not including blocked time), as measured with get_cycles(). */ __u64 pacer_cycles; - + /** * @pacer_lost_cycles: unnecessary delays in transmitting packets * (i.e. wasted output bandwidth) because the pacer was slow or got @@ -2025,13 +2025,13 @@ struct homa_metrics { * @homa->throttled_rpcs is nonempty. */ __u64 pacer_bytes; - + /** * @pacer_skipped_rpcs: total number of times that the pacer had to * abort because it couldn't lock an RPC. */ __u64 pacer_skipped_rpcs; - + /** * @pacer_needed_help: total number of times that homa_check_pacer * found that the pacer was running behind, so it actually invoked @@ -2050,44 +2050,44 @@ struct homa_metrics { * RESEND packets. */ __u64 resent_packets; - + /** * @peer_hash_links: total # of link traversals in homa_peer_find. */ __u64 peer_hash_links; - + /** * @peer_new_entries: total # of new entries created in Homa's * peer table (this value doesn't increment if the desired peer is * found in the entry in its hash chain). */ __u64 peer_new_entries; - + /** * @peer_kmalloc errors: total number of times homa_peer_find * returned an error because it couldn't allocate memory for a new * peer. */ __u64 peer_kmalloc_errors; - + /** * @peer_route errors: total number of times homa_peer_find * returned an error because it couldn't create a route to the peer. */ __u64 peer_route_errors; - + /** * @control_xmit_errors errors: total number of times ip_queue_xmit * failed when transmitting a control packet. */ __u64 control_xmit_errors; - + /** * @data_xmit_errors errors: total number of times ip_queue_xmit * failed when transmitting a data packet. */ __u64 data_xmit_errors; - + /** * @unknown_rpc: total number of times an incoming packet was * discarded because it referred to a nonexistent RPC. Doesn't @@ -2095,32 +2095,32 @@ struct homa_metrics { * fairly common). */ __u64 unknown_rpcs; - + /** * @cant_create_server_rpc: total number of times a server discarded * an incoming packet because it couldn't create a homa_rpc object. */ __u64 server_cant_create_rpcs; - + /** * @unknown_packet_type: total number of times a packet was discarded * because its type wasn't one of the supported values. */ __u64 unknown_packet_types; - + /** * @short_packets: total number of times a packet was discarded * because it was too short to hold all the required information. */ __u64 short_packets; - + /** * @redundant_packets: total number of times a packet was discarded * because all of its they had already been received (perhaps a * resent packet that turned out to be unnecessary?). */ __u64 redundant_packets; - + /** * @resent_packets_used: total number of times a resent packet was * actually incorporated into the message at the target (i.e. it @@ -2132,21 +2132,21 @@ struct homa_metrics { * @peer_timeouts: total number of times a peer (either client or * server) was found to be nonresponsive, resulting in RPC aborts. */ - + __u64 peer_timeouts; /** * @server_rpc_discards: total number of times an RPC was aborted on * the server side because of a timeout. */ - + __u64 server_rpc_discards; /** * @server_rpcs_unknown: total number of times an RPC was aborted on * the server side because it is no longer known to the client. */ - + __u64 server_rpcs_unknown; /** @@ -2232,62 +2232,62 @@ struct homa_metrics { * an RPC because reaping was disabled for that particular RPC */ __u64 disabled_rpc_reaps; - + /** * @reaper_runs: total number of times that the reaper was invoked * and was not disabled. */ __u64 reaper_calls; - + /** * @reaper_dead_skbs: incremented by hsk->dead_skbs each time that * reaper_calls is incremented. */ __u64 reaper_dead_skbs; - + /** * @forced_reaps: total number of times that homa_wait_for_message * invoked the reaper because dead_skbs was too high. */ __u64 forced_reaps; - + /** * @throttle_list_adds: total number of calls to homa_add_to_throttled. */ __u64 throttle_list_adds; - + /** * @throttle_list_checks: number of list elements examined in * calls to homa_add_to_throttled. */ __u64 throttle_list_checks; - + /** * @fifo_grants: total number of times that grants were sent to * the oldest message. */ __u64 fifo_grants; - + /** * @fifo_grants_no_incoming: total number of times that, when a * FIFO grant was issued, the message had no outstanding grants * (everything granted had been received). */ __u64 fifo_grants_no_incoming; - + /** * @unacked_overflows: total number of times that homa_peer_add_ack * found insufficient space for the new id and hence had to send an * ACK message. */ __u64 ack_overflows; - + /** * @ignored_need_acks: total number of times that a NEED_ACK packet * was ignored because the RPC's result hadn't been fully received. */ __u64 ignored_need_acks; - + /** @temp: For temporary use during testing. */ #define NUM_TEMP_METRICS 10 __u64 temp[NUM_TEMP_METRICS]; @@ -2298,7 +2298,7 @@ struct homa_metrics { * core, to hold information that needs to be kept on a per-core basis. */ struct homa_core { - + /** * @last_active: the last time (in get_cycle() units) that * there was system activity, such NAPI or SoftIRQ, on this @@ -2306,7 +2306,7 @@ struct homa_core { * handlers. */ __u64 last_active; - + /** * @last_gro: the last time (in get_cycle() units) that Homa * processed packets at GRO(NAPI) level on this core. Used to @@ -2314,48 +2314,48 @@ struct homa_core { * been used recently for GRO. */ __u64 last_gro; - + /** * @softirq_backlog: the number of batches of packets that have * been queued for SoftIRQ processing on this core but haven't * yet been processed. */ atomic_t softirq_backlog; - + /** * @softirq_offset: used when rotating SoftIRQ assignment among * the next cores; contains an offset to add to the current core * to produce the core for SoftIRQ. */ int softirq_offset; - + /** * held_skb: last packet buffer known to be available for * merging other packets into on this core (note: may not still - * be available), or NULL if none. + * be available), or NULL if none. */ struct sk_buff *held_skb; - + /** * @held_bucket: the index, within napi->gro_hash, of the list * containing @held_skb; undefined if @held_skb is NULL. Used to * verify that @held_skb is still available. */ int held_bucket; - + /** * @thread: the most recent thread to invoke a Homa system call * on this core, or NULL if none. */ struct task_struct *thread; - + /** * @syscall_end_time: the time, in get_cycle() units, when the last * Homa system call completed on this core. Meaningless if thread * is NULL. */ __u64 syscall_end_time; - + /** @metrics: performance statistics for this core. */ struct homa_metrics metrics; }; @@ -2397,7 +2397,7 @@ static inline __u64 homa_local_id(__be64 sender_id) * client RPC. * @hsk: Socket associated with the RPC. * @id: Id of the desired RPC. - * + * * Return: The bucket in which this RPC will appear, if the RPC exists. */ static inline struct homa_rpc_bucket *homa_client_rpc_bucket( @@ -2432,7 +2432,7 @@ inline static void homa_interest_set(struct homa_interest *interest, { interest->peer_addr = rpc->peer->addr; interest->peer_port = rpc->dport; - + /* Must set last for proper synchronization. */ atomic_long_set_release(&interest->id, rpc->id); } @@ -2440,7 +2440,7 @@ inline static void homa_interest_set(struct homa_interest *interest, /** * homa_next_skb() - Compute address of Homa's private link field in @skb. * @skb: Socket buffer containing private link field. - * + * * Homa needs to keep a list of buffers in a message, but it can't use the * links built into sk_buffs because Homa wants to retain its list even * after sending the packet, and the built-in links get used during sending. @@ -2473,7 +2473,7 @@ static inline int homa_port_hash(__u16 port) * server RPC. * @hsk: Socket associated with the RPC. * @id: Id of the desired RPC. - * + * * Return: The bucket in which this RPC will appear, if the RPC exists. */ static inline struct homa_rpc_bucket *homa_server_rpc_bucket( @@ -2555,7 +2555,7 @@ static inline void homa_peer_unlock(struct homa_peer *peer) * be in effect at once. * @hsk: Socket whose RPCs should be protected. Must not be locked * by the caller; will be locked here. - * + * * Return: 1 for success, 0 if the socket has been shutdown, in which * case its RPCs cannot be protected. */ @@ -2672,7 +2672,7 @@ extern struct homa_rpc *homa_find_server_rpc(struct homa_sock *hsk, __be32 saddr, __u16 sport, __u64 id); extern void homa_free_skbs(struct sk_buff *skb); -extern void homa_freeze(struct homa_rpc *rpc, enum homa_freeze_type type, +extern void homa_freeze(struct homa_rpc *rpc, enum homa_freeze_type type, char *format); extern int homa_get_port(struct sock *sk, unsigned short snum); extern void homa_get_resend_range(struct homa_message_in *msgin, @@ -2835,7 +2835,7 @@ static inline void homa_check_pacer(struct homa *homa, int softirq) { if (list_empty(&homa->throttled_rpcs)) return; - + /* The "/2" in the line below gives homa_pacer_main the first chance * to queue new packets; if the NIC queue becomes more than half * empty, then we will help out here. diff --git a/homa_lcache.h b/homa_lcache.h index 77fc9120..d315d6d6 100755 --- a/homa_lcache.h +++ b/homa_lcache.h @@ -73,7 +73,7 @@ static inline void homa_lcache_release(struct homa_lcache *lc) * @id: Id of the desired RPC * @addr: Address of the peer machine for this RPC. * @port: Peer's port for the RPC - * + * * Return: if @lc has a cached lock for @id, return the corresponding * RPC, otherwise return NULL. */ diff --git a/homa_offload.c b/homa_offload.c index 4ecf432b..30bf4495 100644 --- a/homa_offload.c +++ b/homa_offload.c @@ -42,7 +42,7 @@ int homa_offload_init(void) /** * homa_offload_end() - Disables GRO and GSO for Homa; typically invoked * during Homa module unloading. - * + * * Return: nonzero means error. */ int homa_offload_end(void) @@ -62,7 +62,7 @@ static inline void homa_set_softirq_cpu(struct sk_buff *skb, int cpu) { struct rps_sock_flow_table *sock_flow_table; int hash; - + sock_flow_table = rcu_dereference(rps_sock_flow_table); if (sock_flow_table == NULL) return; @@ -86,7 +86,7 @@ static inline void homa_set_softirq_cpu(struct sk_buff *skb, int cpu) * held for possible GRO merging. Note: this list contains * only packets matching a given hash. * @skb: The newly arrived packet. - * + * * Return: If the return value is non-NULL, it refers to an skb in * gro_list. The skb will be removed from the list by the caller and * passed up the stack immediately. @@ -111,7 +111,7 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, struct sk_buff *result = NULL; struct homa_core *core = homa_cores[raw_smp_processor_id()]; __u32 hash; - + // The test below is overly conservative except for data packets. // if (!pskb_may_pull(skb, 64)) // tt_record("homa_gro_receive can't pull enough data " @@ -138,16 +138,16 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, ntohl(ip_hdr(skb)->saddr), homa_local_id(h_new->common.sender_id), h_new->common.type, iph->tos >> 5); - + core->last_active = get_cycles(); - + if (homa->gro_policy & HOMA_GRO_BYPASS) { homa_softirq(skb); - + /* This return value indicates that we have freed skb. */ return ERR_PTR(-EINPROGRESS); } - + /* The GRO mechanism tries to separate packets onto different * gro_lists by hash. This is bad for us, because we want to batch * packets together regardless of their RPCs. So, instead of @@ -163,7 +163,7 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, struct gro_list, list); struct napi_struct *napi = container_of(gro_list, struct napi_struct, gro_hash[hash]); - + /* Make sure that core->held_skb is on the list. */ list_for_each_entry(held_skb, &napi->gro_hash[core->held_bucket].list, list) { @@ -204,7 +204,7 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, goto done; } } - + /* There was no existing Homa packet that this packet could be * batched with, so this packet will become the new merge_skb. * If the packet is sent up the stack before another packet @@ -217,7 +217,7 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, core->held_bucket = hash; if (likely(homa->gro_policy & HOMA_GRO_SAME_CORE)) homa_set_softirq_cpu(skb, raw_smp_processor_id()); - + done: homa_check_pacer(homa, 1); return result; @@ -231,10 +231,10 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, * @skb: The packet for which GRO processing is now finished. * @hoffset: Offset within the packet of the transport header. * - * Return: Always returns 0, signifying success. + * Return: Always returns 0, signifying success. */ int homa_gro_complete(struct sk_buff *skb, int hoffset) -{ +{ struct common_header *h = (struct common_header *) skb_transport_header(skb); struct data_header *d = (struct data_header *) h; @@ -297,7 +297,7 @@ int homa_gro_complete(struct sk_buff *skb, int hoffset) int i, core, best; __u64 best_time = ~0; __u64 last_active; - + /* Pick a specific core to handle SoftIRQ processing for this * group of packets. The goal here is to spread load so that no * core gets overloaded. We do that by checking the next several @@ -334,6 +334,6 @@ int homa_gro_complete(struct sk_buff *skb, int hoffset) target, homa_local_id(h->sender_id), ntohl(d->seg.offset)); } - + return 0; } diff --git a/homa_outgoing.c b/homa_outgoing.c index 40c1defe..dd4ceadf 100644 --- a/homa_outgoing.c +++ b/homa_outgoing.c @@ -47,7 +47,7 @@ inline static void set_priority(struct sk_buff *skb, struct homa_sock *hsk, * @peer: Peer to which the packets will be sent (needed for things like * the MTU). * @iter: Describes the location(s) of message data in user space. - * + * * Return: Address of the first packet in a list of packets linked through * homa_next_skb, or a negative errno if there was an error. No * fields are set in the packet headers except for type, incoming, @@ -75,10 +75,10 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, err = -EINVAL; goto error; } - + dst = homa_get_dst(peer, hsk); mtu = dst_mtu(dst); - + max_pkt_data = mtu - HOMA_IPV4_HEADER_LENGTH - sizeof(struct data_header); if (len <= max_pkt_data) { unsched = max_gso_data = len; @@ -89,7 +89,7 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, gso_size = peer->dst->dev->gso_max_size; if (gso_size > hsk->homa->max_gso_size) gso_size = hsk->homa->max_gso_size; - + /* Round gso_size down to an even # of mtus. */ bufs_per_gso = gso_size/mtu; if (bufs_per_gso == 0) { @@ -100,14 +100,14 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, } max_gso_data = bufs_per_gso * max_pkt_data; gso_size = bufs_per_gso * mtu; - + /* Round unscheduled bytes *up* to an even number of gsos. */ unsched = hsk->homa->rtt_bytes + max_gso_data - 1; unsched -= unsched % max_gso_data; if (unsched > len) unsched = len; } - + /* Copy message data from user space and form sk_buffs. Each * sk_buff may contain multiple data_segments, each of which will * turn into a separate packet, using either TSO in the NIC or @@ -117,7 +117,7 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, struct data_header *h; struct data_segment *seg; int available; - + /* The sizeof32(void*) creates extra space for homa_next_skb. */ skb = alloc_skb(gso_size + HOMA_SKB_EXTRA + sizeof32(void*), GFP_KERNEL); @@ -132,7 +132,7 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; } skb_shinfo(skb)->gso_segs = 0; - + skb_reserve(skb, HOMA_IPV4_HEADER_LENGTH + HOMA_SKB_EXTRA); skb_reset_transport_header(skb); h = (struct data_header *) skb_put(skb, @@ -140,7 +140,7 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, h->common.type = DATA; h->message_length = htonl(len); available = max_gso_data; - + /* Each iteration of the following loop adds one segment * to the buffer. */ @@ -172,7 +172,7 @@ struct sk_buff *homa_fill_packets(struct homa_sock *hsk, struct homa_peer *peer, *last_link = NULL; } return first; - + error: homa_free_skbs(first); return ERR_PTR(err); @@ -200,7 +200,7 @@ void homa_message_out_init(struct homa_rpc *rpc, int sport, struct sk_buff *skb, rpc->msgout.granted = rpc->msgout.length; rpc->msgout.sched_priority = 0; rpc->msgout.init_cycles = get_cycles(); - + /* Must scan the packets to fill in header fields that weren't * known when the packets were allocated. */ @@ -246,7 +246,7 @@ void homa_message_out_destroy(struct homa_message_out *msgout) * @rpc: The packet will go to the socket that handles the other end * of this RPC. Addressing info for the packet, including all of * the fields of common_header except type, will be set from this. - * + * * Return: Either zero (for success), or a negative errno value if there * was a problem. */ @@ -270,7 +270,7 @@ int homa_xmit_control(enum homa_packet_type type, void *contents, * @length: Length of @contents. * @peer: Destination to which the packet will be sent. * @hsk: Socket via which the packet will be sent. - * + * * Return: Either zero (for success), or a negative errno value if there * was a problem. */ @@ -282,7 +282,7 @@ int __homa_xmit_control(void *contents, size_t length, struct homa_peer *peer, int result, priority; struct dst_entry *dst; struct sk_buff *skb; - + /* Allocate the same size sk_buffs as for the smallest data * packets (better reuse of sk_buffs?). */ @@ -293,7 +293,7 @@ int __homa_xmit_control(void *contents, size_t length, struct homa_peer *peer, return -ENOBUFS; dst_hold(dst); skb_dst_set(skb, dst); - + skb_reserve(skb, HOMA_IPV4_HEADER_LENGTH + HOMA_SKB_EXTRA); skb_reset_transport_header(skb); h = (struct common_header *) skb_put(skb, length); @@ -311,7 +311,7 @@ int __homa_xmit_control(void *contents, size_t length, struct homa_peer *peer, result = ip_queue_xmit((struct sock *) hsk, skb, &peer->flow); if (unlikely(result != 0)) { INC_METRIC(control_xmit_errors, 1); - + /* It appears that ip_queue_xmit frees skbuffs after * errors; the following code is to raise an alert if * this isn't actually the case. The extra skb_get above @@ -379,7 +379,7 @@ void homa_xmit_data(struct homa_rpc *rpc, bool force) struct sk_buff *skb = rpc->msgout.next_packet; struct homa *homa = rpc->hsk->homa; int offset = homa_data_offset(skb); - + if (homa == NULL) { printk(KERN_ERR "NULL homa pointer in homa_xmit_" "data, state %d, shutdown %d, id %llu, socket %d", @@ -387,14 +387,14 @@ void homa_xmit_data(struct homa_rpc *rpc, bool force) rpc->hsk->port); BUG(); } - + if (offset >= rpc->msgout.granted) { tt_record3("homa_xmit_data stopping at offset %d " "for id %u: granted is %d", offset, rpc->id, rpc->msgout.granted); break; } - + if ((rpc->msgout.length - offset) >= homa->throttle_min_bytes) { if (!homa_check_nic_queue(homa, skb, force)) { tt_record1("homa_xmit_data adding id %u to " @@ -403,7 +403,7 @@ void homa_xmit_data(struct homa_rpc *rpc, bool force) break; } } - + if (offset < rpc->msgout.unscheduled) { priority = homa_unsched_priority(homa, rpc->peer, rpc->msgout.length); @@ -411,7 +411,7 @@ void homa_xmit_data(struct homa_rpc *rpc, bool force) priority = rpc->msgout.sched_priority; } rpc->msgout.next_packet = *homa_next_skb(skb); - + skb_get(skb); __homa_xmit_data(skb, rpc, priority); force = false; @@ -440,7 +440,7 @@ void __homa_xmit_data(struct sk_buff *skb, struct homa_rpc *rpc, int priority) * created. */ h->cutoff_version = rpc->peer->cutoff_version; - + dst = homa_get_dst(rpc->peer, rpc->hsk); dst_hold(dst); skb_dst_set(skb, dst); @@ -481,10 +481,10 @@ void homa_resend_data(struct homa_rpc *rpc, int start, int end, int priority) { struct sk_buff *skb; - + if (end <= start) return; - + /* The nested loop below scans each data_segment in each * packet, looking for those that overlap the range of * interest. @@ -496,7 +496,7 @@ void homa_resend_data(struct homa_rpc *rpc, int start, int end, int offset, length, count; struct data_segment *seg; struct data_header *h; - + count = skb_shinfo(skb)->gso_segs; if (count < 1) count = 1; @@ -506,12 +506,12 @@ void homa_resend_data(struct homa_rpc *rpc, int start, int end, seg = (struct data_segment *) (skb->head + seg_offset); offset = ntohl(seg->offset); length = ntohl(seg->segment_length); - + if (end <= offset) return; if ((offset + length) <= start) continue; - + /* This segment must be retransmitted. Copy it into * a clean sk_buff. */ @@ -556,7 +556,7 @@ void homa_resend_data(struct homa_rpc *rpc, int start, int end, void homa_outgoing_sysctl_changed(struct homa *homa) { __u64 tmp; - + /* Code below is written carefully to avoid integer underflow or * overflow under expected usage patterns. Be careful when changing! */ @@ -587,7 +587,7 @@ int homa_check_nic_queue(struct homa *homa, struct sk_buff *skb, bool force) { __u64 idle, new_idle, clock; int cycles_for_packet, segs, bytes; - + segs = skb_shinfo(skb)->gso_segs; bytes = skb->tail - skb->transport_header; bytes += HOMA_IPV4_HEADER_LENGTH + HOMA_VLAN_HEADER + HOMA_ETH_OVERHEAD; @@ -614,7 +614,7 @@ int homa_check_nic_queue(struct homa *homa, struct sk_buff *skb, bool force) new_idle = clock + cycles_for_packet; } else new_idle = idle + cycles_for_packet; - + /* This method must be thread-safe. */ if (atomic64_cmpxchg_relaxed(&homa->link_idle_time, idle, new_idle) == idle) @@ -633,15 +633,15 @@ int homa_pacer_main(void *transportInfo) { cycles_t start; struct homa *homa = (struct homa *) transportInfo; - + while (1) { if (homa->pacer_exit) { break; } - + start = get_cycles(); homa_pacer_xmit(homa); - + /* Sleep this thread if the throttled list is empty. Even * if the throttled list isn't empty, call the scheduler * to give other processes a chance to run (if we don't, @@ -679,13 +679,13 @@ void homa_pacer_xmit(struct homa *homa) { struct homa_rpc *rpc; int i; - + /* Make sure only one instance of this function executes at a * time. */ if (!spin_trylock_bh(&homa->pacer_mutex)) return; - + /* Each iteration through the following loop sends one packet. We * limit the number of passes through this loop in order to cap the * time spent in one call to this function (see note in @@ -694,7 +694,7 @@ void homa_pacer_xmit(struct homa *homa) for (i = 0; i < 5; i++) { __u64 idle_time, now; int offset; - + /* If the NIC queue is too long, wait until it gets shorter. */ now = get_cycles(); idle_time = atomic64_read(&homa->link_idle_time); @@ -712,7 +712,7 @@ void homa_pacer_xmit(struct homa *homa) * but we transmit anyway so we don't starve (see perf.text * for more info). */ - + /* Lock the first throttled RPC. This may not be possible * because we have to hold throttle_lock while locking * the RPC; that means we can't wait for the RPC lock because @@ -726,7 +726,7 @@ void homa_pacer_xmit(struct homa *homa) if (homa->pacer_fifo_count <= 0) { __u64 oldest = ~0; struct homa_rpc *cur; - + homa->pacer_fifo_count += 1000; rpc = NULL; list_for_each_entry_rcu(cur, &homa->throttled_rpcs, @@ -749,7 +749,7 @@ void homa_pacer_xmit(struct homa *homa) break; } homa_throttle_unlock(homa); - + offset = homa_rpc_send_offset(rpc); tt_record4("pacer calling homa_xmit_data for rpc id %llu, " "port %d, offset %d, bytes_left %d", @@ -831,7 +831,7 @@ void homa_add_to_throttled(struct homa_rpc *rpc) throttled_links) { int bytes_left_cand; checks++; - + /* Watch out: the pacer might have just transmitted the last * packet from candidate. */ @@ -881,7 +881,7 @@ void homa_log_throttled(struct homa *homa) struct homa_rpc *rpc; int rpcs = 0; int64_t bytes = 0; - + printk(KERN_NOTICE "Printing throttled list\n"); homa_throttle_lock(homa); list_for_each_entry_rcu(rpc, &homa->throttled_rpcs, throttled_links) { diff --git a/homa_peertab.c b/homa_peertab.c index 3594888e..ebf2f89e 100644 --- a/homa_peertab.c +++ b/homa_peertab.c @@ -22,7 +22,7 @@ /** * homa_peertab_init() - Constructor for homa_peertabs. * @peertab: The object to initialize; previous contents are discarded. - * + * * Return: 0 in the normal case, or a negative errno if there was a problem. */ int homa_peertab_init(struct homa_peertab *peertab) @@ -58,7 +58,7 @@ void homa_peertab_destroy(struct homa_peertab *peertab) struct hlist_node *next; if (!peertab->buckets) return; - + for (i = 0; i < HOMA_PEERTAB_BUCKETS; i++) { hlist_for_each_entry_safe(peer, next, &peertab->buckets[i], peertab_links) { @@ -98,7 +98,7 @@ void homa_peertab_gc_dsts(struct homa_peertab *peertab, __u64 now) * @peertab: Peer table in which to perform lookup. * @addr: IPV4 address of the desired host. * @inet: Socket that will be used for sending packets. - * + * * Return: The peer associated with @addr, or a negative errno if an * error occurred. The caller can retain this pointer * indefinitely: peer entries are never deleted except in @@ -120,9 +120,9 @@ struct homa_peer *homa_peer_find(struct homa_peertab *peertab, __be32 addr, } INC_METRIC(peer_hash_links, 1); } - + /* No existing entry; create a new one. - * + * * Note: after we acquire the lock, we have to check again to * make sure the entry still doesn't exist after grabbing * the lock (it might have been created by a concurrent invocation @@ -170,7 +170,7 @@ struct homa_peer *homa_peer_find(struct homa_peertab *peertab, __be32 addr, peer->num_acks = 0; spin_lock_init(&peer->ack_lock); INC_METRIC(peer_new_entries, 1); - + done: spin_unlock_bh(&peertab->write_lock); return peer; @@ -188,7 +188,7 @@ void homa_dst_refresh(struct homa_peertab *peertab, struct homa_peer *peer, { struct rtable *rt; struct sock *sk = &hsk->inet.sk; - + spin_lock_bh(&peertab->write_lock); flowi4_init_output(&peer->flow.u.ip4, sk->sk_bound_dev_if, sk->sk_mark, hsk->inet.tos, RT_SCOPE_UNIVERSE, @@ -213,7 +213,7 @@ void homa_dst_refresh(struct homa_peertab *peertab, struct homa_peer *peer, dst_release(peer->dst); } else { __u64 now = get_cycles(); - + dead->dst = peer->dst; dead->gc_time = now + (cpu_khz<<7); list_add_tail(&dead->dst_links, &peertab->dead_dsts); @@ -230,7 +230,7 @@ void homa_dst_refresh(struct homa_peertab *peertab, struct homa_peer *peer, * @homa: Overall data about the Homa protocol implementation. * @peer: The destination of the message. * @length: Number of bytes in the message. - * + * * Return: A priority level. */ int homa_unsched_priority(struct homa *homa, struct homa_peer *peer, @@ -248,7 +248,7 @@ int homa_unsched_priority(struct homa *homa, struct homa_peer *peer, * homa_peer_set_cutoffs() - Set the cutoffs for unscheduled priorities in * a peer object. This is a convenience function used primarily by unit tests. * @peer: Homa_peer object whose cutoffs should be set. - * @c0: Largest message size that will use priority 0. + * @c0: Largest message size that will use priority 0. * @c1: Largest message size that will use priority 1. * @c2: Largest message size that will use priority 2. * @c3: Largest message size that will use priority 3. @@ -297,7 +297,7 @@ void homa_peer_add_ack(struct homa_rpc *rpc) { struct homa_peer *peer = rpc->peer; struct ack_header ack; - + homa_peer_lock(peer); if (peer->num_acks < NUM_PEER_UNACKED_IDS) { peer->acks[peer->num_acks].client_id = cpu_to_be64(rpc->id); @@ -307,7 +307,7 @@ void homa_peer_add_ack(struct homa_rpc *rpc) homa_peer_unlock(peer); return; } - + /* The peer has filled up; send an ACK message to empty it. The * RPC in the message header will also be considered ACKed. */ @@ -325,23 +325,23 @@ void homa_peer_add_ack(struct homa_rpc *rpc) * @peer: Peer to check for possible unacked RPCs. * @count: Maximum number of acks to return. * @dst: The acks are copied to this location. - * + * * Return: The number of acks extracted from the peer (<= count). */ int homa_peer_get_acks(struct homa_peer *peer, int count, struct homa_ack *dst) -{ +{ /* Don't waste time acquiring the lock if there are no ids available. */ if (peer->num_acks == 0) return 0; - + homa_peer_lock(peer); - + if (count > peer->num_acks) count = peer->num_acks; memcpy(dst, &peer->acks[peer->num_acks - count], count * sizeof(peer->acks[0])); peer->num_acks -= count; - + homa_peer_unlock(peer); return count; } diff --git a/homa_plumbing.c b/homa_plumbing.c index 84381b6d..74276108 100644 --- a/homa_plumbing.c +++ b/homa_plumbing.c @@ -407,7 +407,7 @@ static DECLARE_COMPLETION(timer_thread_done); */ static int __init homa_load(void) { int status; - + printk(KERN_NOTICE "Homa module loading\n"); printk(KERN_NOTICE "Homa structure sizes: data_header %u, " "data_segment %u, ack %u, " @@ -454,13 +454,13 @@ static int __init homa_load(void) { status = -ENOMEM; goto out_cleanup; } - + status = homa_offload_init(); if (status != 0) { printk(KERN_ERR "Homa couldn't init offloads\n"); goto out_cleanup; } - + timer_kthread = kthread_run(homa_timer_main, homa, "homa_timer"); if (IS_ERR(timer_kthread)) { status = PTR_ERR(timer_kthread); @@ -469,9 +469,9 @@ static int __init homa_load(void) { timer_kthread = NULL; goto out_cleanup; } - + tt_init("timetrace", homa->temp); - + return 0; out_cleanup: @@ -492,9 +492,9 @@ static int __init homa_load(void) { static void __exit homa_unload(void) { printk(KERN_NOTICE "Homa module unloading\n"); exiting = true; - + tt_destroy(); - + if (timer_kthread) wake_up_process(timer_kthread); if (homa_offload_end() != 0) @@ -621,7 +621,7 @@ int homa_ioc_recv(struct sock *sk, unsigned long arg) { rpc = NULL; goto error; } - + /* Generate time traces on both ends for long elapsed times (used * for performance debugging). */ @@ -665,7 +665,7 @@ int homa_ioc_recv(struct sock *sk, unsigned long arg) { rpc->state = RPC_IN_SERVICE; } homa_rpc_unlock(rpc); - + args.len = rpc->msgin.total_length; args.source_addr.sin_family = AF_INET; args.source_addr.sin_port = htons(rpc->dport); @@ -678,12 +678,12 @@ int homa_ioc_recv(struct sock *sk, unsigned long arg) { printk(KERN_NOTICE "homa_ioc_recv couldn't copy back args\n"); goto error; } - + if (rpc->error) { err = rpc->error; goto error; } - + result = homa_message_in_copy_data(&rpc->msgin, &iter, iter.count); tt_record4("homa_ioc_recv finished, id %u, peer 0x%x, length %d, pid %d", rpc->id & 0xffffffff, ntohl(rpc->peer->addr), result, @@ -691,7 +691,7 @@ int homa_ioc_recv(struct sock *sk, unsigned long arg) { rpc->dont_reap = false; kfree(iov); return result; - + error: tt_record2("homa_ioc_recv error %d, id %d", err, args.actualId); if (rpc != NULL) { @@ -761,7 +761,7 @@ int homa_ioc_reply(struct sock *sk, unsigned long arg) { err = PTR_ERR(skbs); goto done; } - + srpc = homa_find_server_rpc(hsk, args.dest_addr.sin_addr.s_addr, ntohs(args.dest_addr.sin_port), args.id); if (!srpc) { @@ -807,7 +807,7 @@ int homa_ioc_send(struct sock *sk, unsigned long arg) { struct iov_iter iter; int err; struct homa_rpc *crpc = NULL; - + if (unlikely(copy_from_user(&args, (void *) arg, sizeof(args)))) { err = -EFAULT; goto error; @@ -835,7 +835,7 @@ int homa_ioc_send(struct sock *sk, unsigned long arg) { if (err < 0) goto error; err = 0; - + crpc = homa_rpc_new_client(hsk, &args.dest_addr, &iter); if (IS_ERR(crpc)) { err = PTR_ERR(crpc); @@ -879,7 +879,7 @@ int homa_ioc_abort(struct sock *sk, unsigned long arg) { struct homa_sock *hsk = homa_sk(sk); uint64_t id = (uint64_t) arg; struct homa_rpc *rpc; - + rpc = homa_find_client_rpc(hsk, id); if (rpc == NULL) return -EINVAL; @@ -903,7 +903,7 @@ int homa_ioctl(struct sock *sk, int cmd, unsigned long arg) { struct homa_core *core = homa_cores[raw_smp_processor_id()]; if (current == core->thread) INC_METRIC(user_cycles, start - core->syscall_end_time); - + switch (cmd) { case HOMAIOCSEND: result = homa_ioc_send(sk, arg); @@ -1134,12 +1134,12 @@ int homa_softirq(struct sk_buff *skb) { int num_packets = 0; int pull_length; struct homa_lcache lcache; - + /* Accumulates changes to homa->incoming, to avoid repeated * updates to this shared variable. */ int incoming_delta = 0; - + start = get_cycles(); INC_METRIC(softirq_calls, 1); homa_cores[raw_smp_processor_id()]->last_active = start; @@ -1157,14 +1157,14 @@ int homa_softirq(struct sk_buff *skb) { } } last = start; - + /* skb may actually contain many distinct packets, linked through * skb_shinfo(skb)->frag_list by the Homa GRO mechanism. First, pull * out all the short packets into a separate list, then splice this * list into the front of the packet list, so that all the short * packets will get served first. */ - + skb->next = skb_shinfo(skb)->frag_list; skb_shinfo(skb)->frag_list = NULL; packets = skb; @@ -1186,7 +1186,7 @@ int homa_softirq(struct sk_buff *skb) { next = skb->next; saddr = ip_hdr(skb)->saddr; num_packets++; - + /* The code below makes the header available at skb->data, even * if the packet is fragmented. One complication: it's possible * that the IP header hasn't yet been removed (this happens for @@ -1207,7 +1207,7 @@ int homa_softirq(struct sk_buff *skb) { } if (header_offset) __skb_pull(skb, header_offset); - + h = (struct common_header *) skb->data; if (unlikely((skb->len < sizeof(struct common_header)) || (h->type < DATA) @@ -1223,7 +1223,7 @@ int homa_softirq(struct sk_buff *skb) { INC_METRIC(short_packets, 1); goto discard; } - + if (first_packet) { tt_record4("homa_softirq: first packet from 0x%x:%d, " "id %llu, type %d", @@ -1249,7 +1249,7 @@ int homa_softirq(struct sk_buff *skb) { } goto discard; } - + dport = ntohs(h->dport); hsk = homa_sock_find(&homa->port_map, dport); if (!hsk) { @@ -1259,14 +1259,14 @@ int homa_softirq(struct sk_buff *skb) { homa_local_id(h->sender_id), h->type); goto discard; } - + homa_pkt_dispatch(skb, hsk, &lcache, &incoming_delta); continue; - + discard: kfree_skb(skb); } - + homa_lcache_release(&lcache); atomic_add(incoming_delta, &homa->total_incoming); homa_send_grants(homa); @@ -1303,7 +1303,7 @@ int homa_err_handler(struct sk_buff *skb, u32 info) { const struct iphdr *iph = (const struct iphdr *)skb->data; int type = icmp_hdr(skb)->type; int code = icmp_hdr(skb)->code; - + if ((type == ICMP_DEST_UNREACH) && (code == ICMP_PORT_UNREACH)) { struct common_header *h; char *icmp = (char *) icmp_hdr(skb); @@ -1344,15 +1344,15 @@ __poll_t homa_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait) { struct sock *sk = sock->sk; __poll_t mask; - + /* It seems to be standard practice for poll functions *not* to * acquire the socket lock, so we don't do it here; not sure * why... */ - + sock_poll_wait(file, sock, wait); mask = POLLOUT | POLLWRNORM; - + if (!list_empty(&homa_sk(sk)->ready_requests) || !list_empty(&homa_sk(sk)->ready_responses)) mask |= POLLIN | POLLRDNORM; @@ -1401,7 +1401,7 @@ ssize_t homa_metrics_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { size_t copied; - + if (*offset >= homa->metrics_length) return 0; copied = homa->metrics_length - *offset; @@ -1466,7 +1466,7 @@ int homa_dointvec(struct ctl_table *table, int write, */ homa_incoming_sysctl_changed(homa); homa_outgoing_sysctl_changed(homa); - + /* For this value, only call the method when this * particular value was written (don't want to increment * cutoff_version otherwise). @@ -1475,7 +1475,7 @@ int homa_dointvec(struct ctl_table *table, int write, || (table->data == &homa_data.num_priorities)) { homa_prios_changed(homa); } - + /* Handle the special value log_topic by invoking a function * to print information to the log. */ @@ -1522,7 +1522,7 @@ int homa_timer_main(void *transportInfo) u64 nsec; ktime_t tick_interval; struct hrtimer hrtimer; - + hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer.function = &homa_hrtimer; nsec = 1000000; /* 1 ms */ diff --git a/homa_socktab.c b/homa_socktab.c index f20e7f6b..7d1bf903 100644 --- a/homa_socktab.c +++ b/homa_socktab.c @@ -40,7 +40,7 @@ void homa_socktab_destroy(struct homa_socktab *socktab) { struct homa_socktab_scan scan; struct homa_sock *hsk; - + for (hsk = homa_socktab_start_scan(socktab, &scan); hsk != NULL; hsk = homa_socktab_next(&scan)) { homa_sock_destroy(hsk); @@ -118,7 +118,7 @@ void homa_sock_init(struct homa_sock *hsk, struct homa *homa) { struct homa_socktab *socktab = &homa->port_map; int i; - + mutex_lock(&socktab->write_lock); atomic_set(&hsk->protect_count, 0); spin_lock_init(&hsk->lock); @@ -171,14 +171,14 @@ void homa_sock_shutdown(struct homa_sock *hsk) { struct homa_interest *interest; struct homa_rpc *rpc; - + homa_sock_lock(hsk, "homa_socket_shutdown"); if (hsk->shutdown) { homa_sock_unlock(hsk); return; } printk(KERN_NOTICE "Shutting down socket %d", hsk->port); - + /* The order of cleanup is very important, because there could be * active operations that hold RPC locks but not the socket lock. * 1. Set @shutdown; this ensures that no new RPCs will be created for @@ -196,20 +196,20 @@ void homa_sock_shutdown(struct homa_sock *hsk) hlist_del_rcu(&hsk->socktab_links.hash_links); mutex_unlock(&hsk->homa->port_map.write_lock); homa_sock_unlock(hsk); - + list_for_each_entry_rcu(rpc, &hsk->active_rpcs, active_links) { homa_rpc_lock(rpc); homa_rpc_free(rpc); homa_rpc_unlock(rpc); } - + homa_sock_lock(hsk, "homa_socket_shutdown #2"); list_for_each_entry(interest, &hsk->request_interests, request_links) wake_up_process(interest->thread); list_for_each_entry(interest, &hsk->response_interests, response_links) wake_up_process(interest->thread); homa_sock_unlock(hsk); - + while (!list_empty(&hsk->dead_rpcs)) homa_rpc_reap(hsk, 1000); } @@ -233,7 +233,7 @@ void homa_sock_destroy(struct homa_sock *hsk) * @port: Desired server port for @hsk. If 0, then this call * becomes a no-op: the socket will continue to use * its randomly assigned client port. - * + * * Return: 0 for success, otherwise a negative errno. */ int homa_sock_bind(struct homa_socktab *socktab, struct homa_sock *hsk, @@ -241,7 +241,7 @@ int homa_sock_bind(struct homa_socktab *socktab, struct homa_sock *hsk, { int result = 0; struct homa_sock *owner; - + if (port == 0) return result; if (port >= HOMA_MIN_DEFAULT_PORT) { @@ -270,7 +270,7 @@ int homa_sock_bind(struct homa_socktab *socktab, struct homa_sock *hsk, * @socktab: Hash table in which to perform lookup. * @port: The port of interest. * Return: The socket that owns @port, or NULL if none. - * + * * Note: this function uses RCU list-searching facilities, but it doesn't * call rcu_read_lock. The caller should do that, if the caller cares (this * way, the caller's use of the socket will also be protected). diff --git a/homa_timer.c b/homa_timer.c index 6caaf01b..e7105887 100644 --- a/homa_timer.c +++ b/homa_timer.c @@ -34,7 +34,7 @@ int homa_check_rpc(struct homa_rpc *rpc) struct resend_header resend; struct homa *homa = rpc->hsk->homa; struct homa_peer *peer; - + /* See if we need to request an ack for this RPC. */ if (!homa_is_client(rpc->id) && (rpc->state == RPC_OUTGOING) && (rpc->msgout.next_packet == NULL)) { @@ -54,7 +54,7 @@ int homa_check_rpc(struct homa_rpc *rpc) } } } - + if ((rpc->state == RPC_OUTGOING) && (homa_rpc_send_offset(rpc) < rpc->msgout.granted)) { /* There are granted bytes that we haven't transmitted, so @@ -63,7 +63,7 @@ int homa_check_rpc(struct homa_rpc *rpc) rpc->silent_ticks = 0; return 0; } - + if ((rpc->state == RPC_INCOMING) && ((rpc->msgin.total_length - rpc->msgin.bytes_remaining) >= rpc->msgin.incoming)) { @@ -81,7 +81,7 @@ int homa_check_rpc(struct homa_rpc *rpc) */ if (rpc->silent_ticks < (homa->resend_ticks-1)) return 0; - + peer = rpc->peer; if (peer->outstanding_resends >= rpc->hsk->homa->timeout_resends) { @@ -116,7 +116,7 @@ int homa_check_rpc(struct homa_rpc *rpc) * first on @peer->grantable_rpcs, so it blocks transmissions of * other RPCs. */ - + /* First, collect information that will identify the RPC most * in need of a resend; this will be used during the *next* * homa_timer pass. @@ -128,7 +128,7 @@ int homa_check_rpc(struct homa_rpc *rpc) peer->least_recent_ticks = homa->timer_ticks; peer->current_ticks = homa->timer_ticks; } - + if ((rpc != peer->resend_rpc) || (homa->timer_ticks - rpc->peer->most_recent_resend) < homa->resend_interval) { @@ -145,7 +145,7 @@ int homa_check_rpc(struct homa_rpc *rpc) } return 0; } - + /* Issue a resend for this RPC. */ rpc->resend_timer_ticks = homa->timer_ticks; rpc->peer->most_recent_resend = homa->timer_ticks; @@ -192,7 +192,7 @@ void homa_timer(struct homa *homa) struct homa_peer *dead_peer = NULL; int rpc_count = 0; int total_rpcs = 0; - + start = get_cycles(); homa->timer_ticks++; @@ -212,10 +212,10 @@ void homa_timer(struct homa *homa) break; INC_METRIC(timer_reap_cycles, get_cycles() - start); } - + if (list_empty(&hsk->active_rpcs) || hsk->shutdown) continue; - + if (!homa_protect_rpcs(hsk)) continue; list_for_each_entry_rcu(rpc, &hsk->active_rpcs, active_links) { @@ -256,7 +256,7 @@ void homa_timer(struct homa *homa) */ homa_abort_rpcs(homa, dead_peer->addr, 0, -ETIMEDOUT); } - + if (total_rpcs > 0) tt_record1("homa_timer finished scanning %d RPCs", total_rpcs); diff --git a/homa_utils.c b/homa_utils.c index e432153c..a6effb95 100644 --- a/homa_utils.c +++ b/homa_utils.c @@ -30,7 +30,7 @@ struct completion homa_pacer_kthread_done; /** * homa_init() - Constructor for homa objects. * @homa: Object to initialize. - * + * * Return: 0 on success, or a negative errno if there was an error. Even * if an error occurs, it is safe (and necessary) to call * homa_destroy at some point. @@ -42,7 +42,7 @@ int homa_init(struct homa *homa) int i, err; _Static_assert(HOMA_MAX_PRIORITIES >= 8, "homa_init assumes at least 8 priority levels"); - + /* Initialize core-specific info (if no-one else has already done it), * making sure that each core has private cache lines. */ @@ -70,7 +70,7 @@ int homa_init(struct homa *homa) memset(&core->metrics, 0, sizeof(core->metrics)); } } - + homa->pacer_kthread = NULL; init_completion(&homa_pacer_kthread_done); atomic64_set(&homa->next_outgoing_id, 2); @@ -96,7 +96,7 @@ int homa_init(struct homa *homa) -err); return err; } - + /* Wild guesses to initialize configuration values... */ homa->rtt_bytes = 10000; homa->max_grant_window = 0; @@ -173,7 +173,7 @@ void homa_destroy(struct homa *homa) homa_pacer_stop(homa); wait_for_completion(&homa_pacer_kthread_done); } - + /* The order of the following 2 statements matters! */ homa_socktab_destroy(&homa->port_map); homa_peertab_destroy(&homa->peers); @@ -195,10 +195,10 @@ void homa_destroy(struct homa *homa) * @hsk: Socket to which the RPC belongs. * @dest: Address of host (ip and port) to which the RPC will be sent. * @iter: Describes the location(s) of request message data in user space. - * + * * Return: A printer to the newly allocated object, or a negative * errno if an error occurred. The RPC will be locked; the - * caller must eventually unlock it. + * caller must eventually unlock it. */ struct homa_rpc *homa_rpc_new_client(struct homa_sock *hsk, struct sockaddr_in *dest, struct iov_iter *iter) @@ -208,11 +208,11 @@ struct homa_rpc *homa_rpc_new_client(struct homa_sock *hsk, struct homa_rpc_bucket *bucket; struct sk_buff *skb = NULL; size_t length = iter->count; - + crpc = (struct homa_rpc *) kmalloc(sizeof(*crpc), GFP_KERNEL); if (unlikely(!crpc)) return ERR_PTR(-ENOMEM); - + /* Initialize fields that don't require the socket lock. */ crpc->hsk = hsk; crpc->id = atomic64_fetch_add(2, &hsk->homa->next_outgoing_id); @@ -250,7 +250,7 @@ struct homa_rpc *homa_rpc_new_client(struct homa_sock *hsk, crpc->done_timer_ticks = 0; crpc->magic = HOMA_RPC_MAGIC; crpc->start_cycles = get_cycles(); - + /* Initialize fields that require locking. This allows the most * expensive work, such as copying in the message from user space, * to be performed without holding locks. Also, can't hold spin @@ -267,9 +267,9 @@ struct homa_rpc *homa_rpc_new_client(struct homa_sock *hsk, hlist_add_head(&crpc->hash_links, &bucket->rpcs); list_add_tail_rcu(&crpc->active_links, &hsk->active_rpcs); homa_sock_unlock(hsk); - + return crpc; - + error: homa_free_skbs(skb); kfree(crpc); @@ -283,7 +283,7 @@ struct homa_rpc *homa_rpc_new_client(struct homa_sock *hsk, * @source: IP address (network byte order) of the RPC's client. * @h: Header for the first data packet received for this RPC; used * to initialize the RPC. - * + * * Return: A pointer to a new RPC, which is locked, or a negative errno * if an error occurred. If there is already an RPC corresponding * to h, then it is returned instead of creating a new RPC. @@ -297,13 +297,13 @@ struct homa_rpc *homa_rpc_new_server(struct homa_sock *hsk, struct homa_rpc *srpc; __u64 id = homa_local_id(h->common.sender_id); struct homa_rpc_bucket *bucket = homa_server_rpc_bucket(hsk, id); - + /* Lock the bucket, and make sure no-one else has already created * the desired RPC. */ homa_bucket_lock(bucket, server); hlist_for_each_entry_rcu(srpc, &bucket->rpcs, hash_links) { - if ((srpc->id == id) && + if ((srpc->id == id) && (srpc->dport == ntohs(h->common.sport)) && (srpc->peer->addr == source)) { /* RPC already exists; just return it instead @@ -312,7 +312,7 @@ struct homa_rpc *homa_rpc_new_server(struct homa_sock *hsk, return srpc; } } - + /* Initialize fields that don't require the socket lock. */ srpc = (struct homa_rpc *) kmalloc(sizeof(*srpc), GFP_KERNEL); if (!srpc) { @@ -391,7 +391,7 @@ void homa_rpc_acked(struct homa_sock *hsk, __be32 saddr, struct homa_ack *ack) __u64 id = homa_local_id(ack->client_id); __u16 client_port = ntohs(ack->client_port); __u16 server_port = ntohs(ack->server_port); - + if (hsk2->port != server_port) { /* Without RCU, sockets other than hsk can be deleted * out from under us. @@ -406,7 +406,7 @@ void homa_rpc_acked(struct homa_sock *hsk, __be32 saddr, struct homa_ack *ack) homa_rpc_free(rpc); homa_rpc_unlock(rpc); } - + done: if (hsk->port != server_port) rcu_read_unlock(); @@ -423,7 +423,7 @@ void homa_rpc_free(struct homa_rpc *rpc) int incoming; if (!rpc || (rpc->state == RPC_DEAD)) return; - + /* Before doing anything else, unlink the input message from * homa->grantable_msgs. This will synchronize to ensure that * homa_manage_grants doesn't access this RPC after destruction @@ -431,7 +431,7 @@ void homa_rpc_free(struct homa_rpc *rpc) */ rpc->state = RPC_DEAD; homa_remove_from_grantable(rpc->hsk->homa, rpc); - + /* Unlink from all lists, so no-one will ever find this RPC again. */ homa_sock_lock(rpc->hsk, "homa_rpc_free"); __hlist_del(&rpc->hash_links); @@ -452,13 +452,13 @@ void homa_rpc_free(struct homa_rpc *rpc) // tt_record3("Freeing rpc id %d, socket %d, dead_skbs %d", rpc->id, // rpc->hsk->client_port, // rpc->hsk->dead_skbs); - + /* If the RPC had incoming bytes, remove them from the global count. */ incoming = rpc->msgin.incoming - (rpc->msgin.total_length - rpc->msgin.bytes_remaining); if (incoming != 0) atomic_add(-incoming, &rpc->hsk->homa->total_incoming); - + homa_sock_unlock(rpc->hsk); homa_remove_from_throttled(rpc); } @@ -473,7 +473,7 @@ void homa_rpc_free(struct homa_rpc *rpc) * @hsk: Homa socket that may contain dead RPCs. Must not be locked by the * caller; this function will lock and release. * @count: Number of buffers to free during this call. - * + * * Return: A return value of 0 means that we ran out of work to do; calling * again will do no work (there could be unreaped RPCs, but if so, * reaping has been disabled for them). A value greater than @@ -492,12 +492,12 @@ int homa_rpc_reap(struct homa_sock *hsk, int count) struct homa_rpc *rpc; int i, batch_size; int result; - + INC_METRIC(reaper_calls, 1); INC_METRIC(reaper_dead_skbs, hsk->dead_skbs); - + /* Each iteration through the following loop will reap - * BATCH_MAX skbs. + * BATCH_MAX skbs. */ while (count > 0) { batch_size = count; @@ -505,7 +505,7 @@ int homa_rpc_reap(struct homa_sock *hsk, int count) batch_size = BATCH_MAX; count -= batch_size; num_skbs = num_rpcs = 0; - + homa_sock_lock(hsk, "homa_rpc_reap"); if (atomic_read(&hsk->protect_count)) { INC_METRIC(disabled_reaps, 1); @@ -516,7 +516,7 @@ int homa_rpc_reap(struct homa_sock *hsk, int count) homa_sock_unlock(hsk); return 0; } - + /* Collect buffers and freeable RPCs. */ list_for_each_entry_rcu(rpc, &hsk->dead_rpcs, dead_links) { if (rpc->dont_reap || (atomic_read( @@ -596,7 +596,7 @@ int homa_rpc_reap(struct homa_sock *hsk, int count) * homa_rpc_send_offset() - Return the offset of the first unsent byte of a * message. * @rpc: RPC whose msgout will be examined. - * + * * Return: The first unsent byte for rpc->msgout (0 if the msgout * hasn't been initialized, message length if all bytes have been * sent). @@ -604,7 +604,7 @@ int homa_rpc_reap(struct homa_sock *hsk, int count) int homa_rpc_send_offset(struct homa_rpc *rpc) { struct sk_buff *pkt = rpc->msgout.next_packet; - + if (rpc->msgout.length < 0) return 0; if (!pkt) @@ -617,7 +617,7 @@ int homa_rpc_send_offset(struct homa_rpc *rpc) * a packet belongs to, if there is any. Thread-safe without socket lock. * @hsk: Socket via which packet was received. * @id: Unique identifier for the RPC. - * + * * Return: A pointer to the homa_rpc for this id, or NULL if none. * The RPC will be locked; the caller must eventually unlock it * by invoking homa_unlock_client_rpc. @@ -643,7 +643,7 @@ struct homa_rpc *homa_find_client_rpc(struct homa_sock *hsk, __u64 id) * @saddr: Address from which the packet was sent. * @sport: Port at @saddr from which the packet was sent. * @id: Unique identifier for the RPC (must have server bit set). - * + * * Return: A pointer to the homa_rpc matching the arguments, or NULL * if none. The RPC will be locked; the caller must eventually * unlock it by invoking homa_unlock_server_rpc. @@ -673,7 +673,7 @@ void homa_rpc_log(struct homa_rpc *rpc) { char *type = homa_is_client(rpc->id) ? "Client" : "Server"; char *peer = homa_print_ipv4_addr(rpc->peer->addr); - + if (rpc->state == RPC_INCOMING) printk(KERN_NOTICE "%s RPC INCOMING, id %llu, peer %s:%d, " "%d/%d bytes received, incoming %d\n", @@ -718,14 +718,14 @@ void homa_rpc_log_active(struct homa *homa, uint64_t id) struct homa_sock *hsk; struct homa_rpc *rpc; int count = 0; - + printk("Logging active Homa RPCs:\n"); rcu_read_lock(); for (hsk = homa_socktab_start_scan(&homa->port_map, &scan); hsk != NULL; hsk = homa_socktab_next(&scan)) { if (list_empty(&hsk->active_rpcs) || hsk->shutdown) continue; - + if (!homa_protect_rpcs(hsk)) continue; list_for_each_entry_rcu(rpc, &hsk->active_rpcs, active_links) { @@ -744,12 +744,12 @@ void homa_rpc_log_active(struct homa *homa, uint64_t id) * homa_print_ipv4_addr() - Convert an IPV4 address to the standard string * representation. * @addr: Address to convert, in network byte order. - * + * * Return: The converted value. Values are stored in static memory, so * the caller need not free. This also means that storage is * eventually reused (there are enough buffers to accommodate * multiple "active" values). - * + * * Note: Homa uses this function, rather than the %pI4 format specifier * for snprintf et al., because the kernel's version of snprintf isn't * available in Homa's unit test environment. @@ -776,14 +776,14 @@ char *homa_print_ipv4_addr(__be32 addr) * @skb: Packet whose information should be printed. * @buffer: Buffer in which to generate the string. * @buf_len: Number of bytes available at @buffer. - * + * * Return: @buffer */ char *homa_print_packet(struct sk_buff *skb, char *buffer, int buf_len) { int used = 0; struct common_header *common = (struct common_header *) skb->data; - + used = homa_snprintf(buffer, buf_len, used, "%s from %s:%u, dport %d, id %llu", homa_symbol_for_type(common->type), @@ -882,7 +882,7 @@ char *homa_print_packet(struct sk_buff *skb, char *buffer, int buf_len) break; } } - + buffer[buf_len-1] = 0; return buffer; } @@ -894,7 +894,7 @@ char *homa_print_packet(struct sk_buff *skb, char *buffer, int buf_len) * @skb: Packet whose information should be printed. * @buffer: Buffer in which to generate the string. * @buf_len: Number of bytes available at @buffer. - * + * * Return: @buffer */ char *homa_print_packet_short(struct sk_buff *skb, char *buffer, int buf_len) @@ -907,7 +907,7 @@ char *homa_print_packet_short(struct sk_buff *skb, char *buffer, int buf_len) struct data_segment *seg; int bytes_left, used, i; int seg_length = ntohl(h->seg.segment_length); - + used = homa_snprintf(buffer, buf_len, 0, "DATA%s %d@%d", h->retransmit ? " retrans" : "", seg_length, ntohl(h->seg.offset)); @@ -942,7 +942,7 @@ char *homa_print_packet_short(struct sk_buff *skb, char *buffer, int buf_len) case BUSY: snprintf(buffer, buf_len, "BUSY"); break; - case CUTOFFS: + case CUTOFFS: snprintf(buffer, buf_len, "CUTOFFS"); break; case FREEZE: @@ -977,20 +977,20 @@ char *homa_print_packet_short(struct sk_buff *skb, char *buffer, int buf_len) * followed by values for the various substitutions requested * in @format * @ ... - * + * * Return: The number of characters now occupied in @buffer, not - * including the terminating null character. + * including the terminating null character. */ int homa_snprintf(char *buffer, int size, int used, const char* format, ...) { int new_chars; - + va_list ap; va_start(ap, format); - + if (used >= (size-1)) return used; - + new_chars = vsnprintf(buffer + used, size - used, format, ap); if (new_chars < 0) return used; @@ -1003,7 +1003,7 @@ int homa_snprintf(char *buffer, int size, int used, const char* format, ...) * homa_symbol_for_state() - Returns a printable string describing an * RPC state. * @rpc: RPC whose state should be returned in printable form. - * + * * Return: A static string holding the current state of @rpc. */ char *homa_symbol_for_state(struct homa_rpc *rpc) @@ -1021,7 +1021,7 @@ char *homa_symbol_for_state(struct homa_rpc *rpc) case RPC_DEAD: return "DEAD"; } - + /* See safety comment in homa_symbol_for_type. */ snprintf(buffer, sizeof(buffer)-1, "unknown(%u)", rpc->state); buffer[sizeof(buffer)-1] = 0; @@ -1031,7 +1031,7 @@ char *homa_symbol_for_state(struct homa_rpc *rpc) /** * homa_symbol_for_type() - Returns a printable string describing a packet type. * @type: A value from those defined by &homa_packet_type. - * + * * Return: A static string holding the packet type corresponding to @type. */ char *homa_symbol_for_type(uint8_t type) @@ -1057,7 +1057,7 @@ char *homa_symbol_for_type(uint8_t type) case ACK: return "ACK"; } - + /* Using a static buffer can produce garbled text under concurrency, * but (a) it's unlikely (this code only executes if the opcode is * bogus), (b) this is mostly for testing and debugging, and (c) the @@ -1081,7 +1081,7 @@ void homa_append_metric(struct homa *homa, const char* format, ...) char *new_buffer; size_t new_chars; va_list ap; - + if (!homa->metrics) { #ifdef __UNIT_TEST__ homa->metrics_capacity = 30; @@ -1096,7 +1096,7 @@ void homa_append_metric(struct homa *homa, const char* format, ...) } homa->metrics_length = 0; } - + /* May have to execute this loop multiple times if we run out * of space in homa->metrics; each iteration expands the storage, * until eventually it is large enough. @@ -1109,7 +1109,7 @@ void homa_append_metric(struct homa *homa, const char* format, ...) va_end(ap); if ((homa->metrics_length + new_chars) < homa->metrics_capacity) break; - + /* Not enough room; expand buffer capacity. */ homa->metrics_capacity *= 2; new_buffer = kmalloc(homa->metrics_capacity, GFP_KERNEL); @@ -1130,13 +1130,13 @@ void homa_append_metric(struct homa *homa, const char* format, ...) * generate a human-readable string describing all of them. * @homa: Overall data about the Homa protocol implementation; * the formatted string will be stored in homa->metrics. - * - * Return: The formatted string. + * + * Return: The formatted string. */ char *homa_print_metrics(struct homa *homa) { int core, i, lower = 0; - + homa->metrics_length = 0; homa_append_metric(homa, "rdtsc_cycles %20llu " @@ -1534,15 +1534,15 @@ char *homa_print_metrics(struct homa *homa) void homa_prios_changed(struct homa *homa) { int i; - + if (homa->num_priorities > HOMA_MAX_PRIORITIES) homa->num_priorities = HOMA_MAX_PRIORITIES; - + /* This guarantees that we will choose priority 0 if nothing else * in the cutoff array matches. */ homa->unsched_cutoffs[0] = INT_MAX; - + for (i = HOMA_MAX_PRIORITIES-1; ; i--) { if (i >= homa->num_priorities) { homa->unsched_cutoffs[i] = 0; diff --git a/perf.txt b/perf.txt index be8c0a44..7c9880dd 100644 --- a/perf.txt +++ b/perf.txt @@ -97,10 +97,10 @@ order. seems to be in kernel call time and NIC->NIC time. Also, note that the 5.4.80 times have improved considerably from January 2021; there appears to be at least 1 us variation in RTT from machine to machine. - 5.17.7 5.4.80 + 5.17.7 5.4.80 Server Client Server Client ---------------------------------------------------------- -Send: +Send: homa_send/reply 461 588 468 534 IP/Driver 514 548 508 522 Total 975 1136 1475 1056 @@ -392,7 +392,7 @@ Event Median threads happened (randomly) to get busy on that core the same time, and they completely monopolized the core. * (March 2020) Linux switches threads between cores very frequently when - threads sleep (2/3 of the time in experiments today). + threads sleep (2/3 of the time in experiments today). * (Feb. 2020) The pacer can potentially be a severe performance bottleneck (a single thread cannot keep the network utilized with packets that are diff --git a/test/Makefile b/test/Makefile index 49aec004..73041893 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,7 +3,7 @@ KERNEL_DIR := /lib/modules/$(shell uname -r)/build PERL ?= perl ARCH ?= x86 - + CINCLUDES := -I. \ -I.. \ -I$(KERNEL_DIR)/arch/x86/include \ @@ -24,7 +24,7 @@ CCINCLUDES := -I. \ -I$(KERNEL_DIR)/arch/x86/include/uapi \ -I$(KERNEL_DIR)/arch/x86/include/generated/uapi \ -I$(KERNEL_DIR)/include/uapi \ - -I$(KERNEL_DIR)/include/generated/uapi + -I$(KERNEL_DIR)/include/generated/uapi DEFS := -D__KERNEL__ \ -D__UNIT_TEST__ \ @@ -33,7 +33,7 @@ DEFS := -D__KERNEL__ \ WARNS := -Wall -Wundef -Wno-trigraphs -Wno-sign-compare -Wno-strict-aliasing CFLAGS := $(WARNS) -Wstrict-prototypes -MD -g $(CINCLUDES) $(DEFS) CCFLAGS := -std=c++11 $(WARNS) -MD -g $(CCINCLUDES) $(DEFS) -fsanitize=address - + TEST_SRCS := unit_homa_incoming.c \ unit_homa_lcache.c \ unit_homa_offload.c \ @@ -45,7 +45,7 @@ TEST_SRCS := unit_homa_incoming.c \ unit_homa_utils.c \ unit_timetrace.c TEST_OBJS := $(patsubst %.c,%.o,$(TEST_SRCS)) - + HOMA_SRCS := homa_incoming.c \ homa_offload.c \ homa_outgoing.c \ @@ -56,16 +56,16 @@ HOMA_SRCS := homa_incoming.c \ homa_utils.c \ timetrace.c HOMA_OBJS := $(patsubst %.c,%.o,$(HOMA_SRCS)) - + OTHER_SRCS := ccutils.cc \ main.c \ mock.c \ utils.c - + OTHER_OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(OTHER_SRCS))) - + OBJS := $(TEST_OBJS) $(HOMA_OBJS) $(OTHER_OBJS) - + CLEANS = unit $(OBJS) *.d .deps all: run_tests @@ -73,7 +73,7 @@ all: run_tests # This seems to be the only way to disable the built-in implicit rules # for %:%.c and %:%.cc. .SUFFIXES: - + %.o: ../%.c cc -c $(CFLAGS) $< -o $@ %.e: ../%.c @@ -86,16 +86,16 @@ all: run_tests g++ -c $(CCFLAGS) $< -o $@ %.e: %.cc g++ -E $(CCFLAGS) $< -o $@ - + unit: $(OBJS) g++ $(CFLAGS) $^ -o $@ -lasan - + run_tests: unit ./unit clean: rm -f unit $(CLEANS) - + # This magic (along with the -MD gcc option) automatically generates makefile # dependencies for header files included from C source files we compile, # and keeps those dependencies up-to-date every time we recompile. @@ -109,4 +109,4 @@ clean: # prints the value of a make variable. print-%: @echo $* = $($*) - + diff --git a/test/ccutils.cc b/test/ccutils.cc index 0c36d512..238d6d8d 100644 --- a/test/ccutils.cc +++ b/test/ccutils.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022, Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/ccutils.h b/test/ccutils.h index d07ff2f0..bd33768f 100644 --- a/test/ccutils.h +++ b/test/ccutils.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022, Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,7 +30,7 @@ CEXTERN void unit_hash_free(struct unit_hash *hash); CEXTERN void *unit_hash_get(struct unit_hash *hash, const void *key); CEXTERN struct unit_hash * unit_hash_new(void); -CEXTERN void unit_hash_set(struct unit_hash *hash, const void *key, +CEXTERN void unit_hash_set(struct unit_hash *hash, const void *key, void *value); CEXTERN int unit_hash_size(struct unit_hash *hash); CEXTERN void unit_log_add_separator(char *sep); diff --git a/test/kselftest_harness.h b/test/kselftest_harness.h index c6927e08..30faa751 100644 --- a/test/kselftest_harness.h +++ b/test/kselftest_harness.h @@ -804,7 +804,7 @@ static int test_harness_run(int __attribute__((unused)) argc, unsigned int count = 0; unsigned int pass_count = 0; int argi = 1; - + for (argi = 1; argi < argc; argi++) { if ((strcmp(argv[argi], "-v") == 0) || (strcmp(argv[argi], "--verbose") == 0)) { diff --git a/test/main.c b/test/main.c index d9ed75d1..51c8b2a5 100644 --- a/test/main.c +++ b/test/main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022, Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/mock.c b/test/mock.c index 6e18d38c..ca38aa35 100644 --- a/test/mock.c +++ b/test/mock.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/mock.h b/test/mock.h index 7eef1f26..c5d2ea12 100644 --- a/test/mock.h +++ b/test/mock.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/unit_homa_incoming.c b/test/unit_homa_incoming.c index 6b0b9c01..2845fb5b 100644 --- a/test/unit_homa_incoming.c +++ b/test/unit_homa_incoming.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Stanford University +/* Copyright (c) 2019-2022, Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/unit_homa_lcache.c b/test/unit_homa_lcache.c index 9128a9a2..72220a72 100644 --- a/test/unit_homa_lcache.c +++ b/test/unit_homa_lcache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 20221, Stanford University +/* Copyright (c) 2021-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/unit_homa_offload.c b/test/unit_homa_offload.c index aeded8bd..df702706 100644 --- a/test/unit_homa_offload.c +++ b/test/unit_homa_offload.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,7 +51,7 @@ FIXTURE_SETUP(homa_offload) self->napi.gro_hash[i].count = 0; } self->napi.gro_bitmask = 0; - + self->skb = mock_skb_new(self->ip, &self->header.common, 1400, self->header.seg.offset); NAPI_GRO_CB(self->skb)->same_flow = 0; @@ -74,7 +74,7 @@ FIXTURE_SETUP(homa_offload) FIXTURE_TEARDOWN(homa_offload) { struct sk_buff *skb, *tmp; - + list_for_each_entry_safe(skb, tmp, &self->napi.gro_hash[2].list, list) kfree_skb(skb); homa_destroy(&self->homa); @@ -120,7 +120,7 @@ TEST_F(homa_offload, homa_gro_receive__merge) int same_flow; homa_cores[cpu_number]->held_skb = self->skb2; homa_cores[cpu_number]->held_bucket = 2; - + self->header.seg.offset = htonl(6000); self->header.common.sender_id = cpu_to_be64(1002); skb = mock_skb_new(self->ip, &self->header.common, 1400, 0); @@ -129,7 +129,7 @@ TEST_F(homa_offload, homa_gro_receive__merge) same_flow = NAPI_GRO_CB(skb)->same_flow; EXPECT_EQ(1, same_flow); EXPECT_EQ(2, NAPI_GRO_CB(self->skb2)->count); - + self->header.seg.offset = htonl(7000); self->header.common.sender_id = cpu_to_be64(1004); skb2 = mock_skb_new(self->ip, &self->header.common, 1400, 0); @@ -138,7 +138,7 @@ TEST_F(homa_offload, homa_gro_receive__merge) same_flow = NAPI_GRO_CB(skb)->same_flow; EXPECT_EQ(1, same_flow); EXPECT_EQ(3, NAPI_GRO_CB(self->skb2)->count); - + unit_log_frag_list(self->skb2, 1); EXPECT_STREQ("DATA from 196.168.0.1:40000, dport 88, id 1002, " "message_length 10000, offset 6000, " @@ -151,7 +151,7 @@ TEST_F(homa_offload, homa_gro_receive__merge) TEST_F(homa_offload, homa_gro_receive__max_gro_skbs) { struct sk_buff *skb; - + // First packet: fits below the limit. homa->max_gro_skbs = 3; homa_cores[cpu_number]->held_skb = self->skb2; @@ -161,7 +161,7 @@ TEST_F(homa_offload, homa_gro_receive__max_gro_skbs) homa_gro_receive(&self->napi.gro_hash[3].list, skb); EXPECT_EQ(2, NAPI_GRO_CB(self->skb2)->count); EXPECT_EQ(2, self->napi.gro_hash[2].count); - + // Second packet hits the limit. self->header.common.sport = htons(40001); skb = mock_skb_new(self->ip, &self->header.common, 1400, 0); @@ -175,7 +175,7 @@ TEST_F(homa_offload, homa_gro_receive__max_gro_skbs) kfree_skb(self->skb2); EXPECT_EQ(1, self->napi.gro_hash[2].count); EXPECT_EQ(6, self->napi.gro_bitmask); - + // Third packet also hits the limit for skb, causing the bucket // to become empty. homa->max_gro_skbs = 2; @@ -208,12 +208,12 @@ TEST_F(homa_offload, homa_gro_complete__GRO_IDLE_NEW) homa_cores[1]->last_gro = 899; atomic_set(&homa_cores[2]->softirq_backlog, 0); homa_cores[2]->last_gro = 0; - + // Avoid busy cores. homa_gro_complete(self->skb, 0); EXPECT_EQ(1, self->skb->hash - 32); EXPECT_EQ(1, atomic_read(&homa_cores[1]->softirq_backlog)); - + // All cores busy; must rotate. homa_gro_complete(self->skb, 0); EXPECT_EQ(6, self->skb->hash - 32); @@ -237,16 +237,16 @@ TEST_F(homa_offload, homa_gro_complete__GRO_IDLE) homa_cores[0]->last_active = 20; homa_cores[1]->last_active = 15; homa_cores[2]->last_active = 10; - + cpu_number = 5; homa_gro_complete(self->skb, 0); EXPECT_EQ(1, self->skb->hash - 32); - + homa_cores[6]->last_active = 5; cpu_number = 5; homa_gro_complete(self->skb, 0); EXPECT_EQ(6, self->skb->hash - 32); - + cpu_number = 6; homa_gro_complete(self->skb, 0); EXPECT_EQ(2, self->skb->hash - 32); diff --git a/test/unit_homa_outgoing.c b/test/unit_homa_outgoing.c index bfe803fa..f90593b6 100644 --- a/test/unit_homa_outgoing.c +++ b/test/unit_homa_outgoing.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -63,11 +63,11 @@ TEST_F(homa_outgoing, set_priority__priority_mapping) { struct homa_rpc *srpc; struct grant_header h; - + srpc = unit_server_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->client_port, 1111, 10000, 10000); ASSERT_NE(NULL, srpc); - + h.offset = htonl(12345); h.priority = 4; EXPECT_EQ(0, homa_xmit_control(GRANT, &h, sizeof(h), srpc)); @@ -157,7 +157,7 @@ TEST_F(homa_outgoing, homa_fill_packets__set_gso_info) homa_rpc_unlock(crpc); unit_log_clear(); EXPECT_EQ(1420, skb_shinfo(crpc->msgout.packets)->gso_size); - + // Second message: no GSO (message fits in one packet) mock_net_device.gso_max_size = 10000; self->homa.max_gso_size = 4200; @@ -167,7 +167,7 @@ TEST_F(homa_outgoing, homa_fill_packets__set_gso_info) homa_rpc_unlock(crpc); unit_log_clear(); EXPECT_EQ(0, skb_shinfo(crpc->msgout.packets)->gso_size); - + // Third message: GSO limit is one packet mock_net_device.gso_max_size = 10000; self->homa.max_gso_size = 1000; @@ -287,13 +287,13 @@ TEST_F(homa_outgoing, homa_xmit_control__server_request) { struct homa_rpc *srpc; struct grant_header h; - + homa_sock_bind(&self->homa.port_map, &self->hsk, self->server_port); srpc = unit_server_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->client_port, self->server_id, 10000, 10000); ASSERT_NE(NULL, srpc); - + h.offset = htonl(12345); h.priority = 4; h.common.sender_id = cpu_to_be64(self->client_id); @@ -308,13 +308,13 @@ TEST_F(homa_outgoing, homa_xmit_control__client_response) { struct homa_rpc *crpc; struct grant_header h; - + crpc = unit_client_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->server_port, self->client_id, 100, 10000); ASSERT_NE(NULL, crpc); unit_log_clear(); - + h.offset = htonl(12345); h.priority = 4; mock_xmit_log_verbose = 1; @@ -329,11 +329,11 @@ TEST_F(homa_outgoing, __homa_xmit_control__cant_alloc_skb) { struct homa_rpc *srpc; struct grant_header h; - + srpc = unit_server_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->client_port, 1111, 10000, 10000); ASSERT_NE(NULL, srpc); - + h.common.type = GRANT; h.offset = htonl(12345); h.priority = 4; @@ -347,7 +347,7 @@ TEST_F(homa_outgoing, __homa_xmit_control__pad_packet) { struct homa_rpc *srpc; struct busy_header h; - + srpc = unit_server_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->client_port, 1111, 10000, 10000); ASSERT_NE(NULL, srpc); @@ -361,11 +361,11 @@ TEST_F(homa_outgoing, __homa_xmit_control__ip_queue_xmit_error) { struct homa_rpc *srpc; struct grant_header h; - + srpc = unit_server_rpc(&self->hsk, RPC_INCOMING, self->client_ip, self->server_ip, self->client_port, 1111, 10000, 10000); ASSERT_NE(NULL, srpc); - + h.offset = htonl(12345); h.priority = 4; mock_xmit_log_verbose = 1; @@ -436,7 +436,7 @@ TEST_F(homa_outgoing, homa_xmit_data__stop_because_no_more_granted) ASSERT_FALSE(IS_ERR(crpc1)); homa_rpc_unlock(crpc1); unit_log_clear(); - + crpc1->msgout.granted = 1000; homa_xmit_data(crpc1, false); EXPECT_STREQ("xmit DATA 1400@0", unit_log_get()); @@ -454,7 +454,7 @@ TEST_F(homa_outgoing, homa_xmit_data__throttle) atomic64_set(&self->homa.link_idle_time, 11000); self->homa.max_nic_queue_cycles = 3000; self->homa.flags &= ~HOMA_FLAG_DONT_THROTTLE; - + homa_xmit_data(crpc1, false); EXPECT_STREQ("xmit DATA 1400@0; " "xmit DATA 1400@1400; " @@ -473,7 +473,7 @@ TEST_F(homa_outgoing, homa_xmit_data__force) homa_rpc_unlock(crpc1); ASSERT_FALSE(IS_ERR(crpc2)); homa_rpc_unlock(crpc2); - + /* First, get an RPC on the throttled list. */ atomic64_set(&self->homa.link_idle_time, 11000); self->homa.max_nic_queue_cycles = 3000; @@ -482,7 +482,7 @@ TEST_F(homa_outgoing, homa_xmit_data__force) unit_log_clear(); unit_log_throttled(&self->homa); EXPECT_STREQ("request 2, next_offset 2800", unit_log_get()); - + /* Now force transmission. */ unit_log_clear(); homa_xmit_data(crpc2, true); @@ -518,7 +518,7 @@ TEST_F(homa_outgoing, __homa_xmit_data__fill_dst) unit_log_clear(); dst = crpc->peer->dst; old_refcount = dst->__refcnt.counter; - + skb_get(crpc->msgout.packets); __homa_xmit_data(crpc->msgout.packets, crpc, 6); EXPECT_STREQ("xmit DATA 1000@0", unit_log_get()); @@ -560,20 +560,20 @@ TEST_F(homa_outgoing, homa_resend_data__basics) "incoming 11200, RETRANSMIT", unit_log_get()); EXPECT_STREQ("2 2 2", mock_xmit_prios); - + unit_log_clear(); mock_clear_xmit_prios(); mock_xmit_log_verbose = 0; homa_resend_data(crpc, 1500, 1500, 3); EXPECT_STREQ("", unit_log_get()); - + unit_log_clear(); mock_clear_xmit_prios(); mock_xmit_log_verbose = 0; homa_resend_data(crpc, 2800, 4200, 3); EXPECT_STREQ("xmit DATA retrans 1400@2800", unit_log_get()); EXPECT_STREQ("3", mock_xmit_prios); - + unit_log_clear(); mock_clear_xmit_prios(); mock_xmit_log_verbose = 0; @@ -581,7 +581,7 @@ TEST_F(homa_outgoing, homa_resend_data__basics) EXPECT_STREQ("xmit DATA retrans 1400@2800; " "xmit DATA retrans 1400@4200", unit_log_get()); EXPECT_STREQ("7 7", mock_xmit_prios); - + unit_log_clear(); mock_xmit_log_verbose = 0; homa_resend_data(crpc, 16000, 17000, 7); @@ -599,11 +599,11 @@ TEST_F(homa_outgoing, homa_resend_data__set_incoming) EXPECT_EQ(10000, crpc->msgout.granted); homa_resend_data(crpc, 8400, 8800, 2); EXPECT_SUBSTR("incoming 10000", unit_log_get()); - + unit_log_clear(); homa_resend_data(crpc, 9800, 10000, 2); EXPECT_SUBSTR("incoming 11200", unit_log_get()); - + unit_log_clear(); homa_resend_data(crpc, 15500, 16500, 2); EXPECT_SUBSTR("incoming 16000", unit_log_get()); @@ -614,15 +614,15 @@ TEST_F(homa_outgoing, homa_outgoing_sysctl_changed) self->homa.link_mbps = 10000; homa_outgoing_sysctl_changed(&self->homa); EXPECT_EQ(808, self->homa.cycles_per_kbyte); - + self->homa.link_mbps = 1000; homa_outgoing_sysctl_changed(&self->homa); EXPECT_EQ(8080, self->homa.cycles_per_kbyte); - + self->homa.link_mbps = 40000; homa_outgoing_sysctl_changed(&self->homa); EXPECT_EQ(202, self->homa.cycles_per_kbyte); - + self->homa.max_nic_queue_ns = 200; cpu_khz = 2000000; homa_outgoing_sysctl_changed(&self->homa); @@ -774,7 +774,7 @@ TEST_F(homa_outgoing, homa_pacer_xmit__xmit_fifo) ASSERT_FALSE(IS_ERR(crpc3)); homa_rpc_unlock(crpc3); homa_add_to_throttled(crpc3); - + /* First attempt: pacer_fifo_count doesn't reach zero. */ self->homa.max_nic_queue_cycles = 1300; self->homa.pacer_fifo_count = 200; @@ -791,7 +791,7 @@ TEST_F(homa_outgoing, homa_pacer_xmit__xmit_fifo) "request 2, next_offset 0; " "request 6, next_offset 0", unit_log_get()); EXPECT_EQ(50, self->homa.pacer_fifo_count); - + /* Second attempt: pacer_fifo_count reaches zero. */ atomic64_set(&self->homa.link_idle_time, 10000); unit_log_clear(); @@ -916,13 +916,13 @@ TEST_F(homa_outgoing, homa_add_to_throttled__basics) homa_rpc_unlock(crpc3); homa_rpc_unlock(crpc4); homa_rpc_unlock(crpc5); - + /* Basics: add one RPC. */ homa_add_to_throttled(crpc1); unit_log_clear(); unit_log_throttled(&self->homa); EXPECT_STREQ("request 2, next_offset 0", unit_log_get()); - + /* Check priority ordering. */ homa_add_to_throttled(crpc2); homa_add_to_throttled(crpc3); @@ -935,7 +935,7 @@ TEST_F(homa_outgoing, homa_add_to_throttled__basics) "request 10, next_offset 0; " "request 8, next_offset 0; " "request 6, next_offset 0", unit_log_get()); - + /* Don't reinsert if already present. */ homa_add_to_throttled(crpc1); unit_log_clear(); @@ -960,15 +960,15 @@ TEST_F(homa_outgoing, homa_add_to_throttled__inc_metrics) homa_rpc_unlock(crpc1); homa_rpc_unlock(crpc2); homa_rpc_unlock(crpc3); - + homa_add_to_throttled(crpc1); EXPECT_EQ(1, homa_cores[cpu_number]->metrics.throttle_list_adds); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.throttle_list_checks); - + homa_add_to_throttled(crpc2); EXPECT_EQ(2, homa_cores[cpu_number]->metrics.throttle_list_adds); EXPECT_EQ(1, homa_cores[cpu_number]->metrics.throttle_list_checks); - + homa_add_to_throttled(crpc3); EXPECT_EQ(3, homa_cores[cpu_number]->metrics.throttle_list_adds); EXPECT_EQ(3, homa_cores[cpu_number]->metrics.throttle_list_checks); @@ -980,16 +980,16 @@ TEST_F(homa_outgoing, homa_remove_from_throttled) &self->server_addr, unit_iov_iter((void *) 1000, 5000)); ASSERT_FALSE(IS_ERR(crpc)); homa_rpc_unlock(crpc); - + homa_add_to_throttled(crpc); EXPECT_FALSE(list_empty(&self->homa.throttled_rpcs)); - + // First attempt will remove. unit_log_clear(); homa_remove_from_throttled(crpc); EXPECT_TRUE(list_empty(&self->homa.throttled_rpcs)); EXPECT_STREQ("removing id 2 from throttled list", unit_log_get()); - + // Second attempt: nothing to do. unit_log_clear(); homa_remove_from_throttled(crpc); diff --git a/test/unit_homa_peertab.c b/test/unit_homa_peertab.c index 2b5fd3f3..ce88e126 100644 --- a/test/unit_homa_peertab.c +++ b/test/unit_homa_peertab.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -61,19 +61,19 @@ static void peer_spinlock_hook(void) TEST_F(homa_peertab, homa_peer_find__basics) { struct homa_peer *peer, *peer2; - + peer = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(11111, peer->addr); EXPECT_EQ(INT_MAX, peer->unsched_cutoffs[HOMA_MAX_PRIORITIES-2]); EXPECT_EQ(0, peer->cutoff_version); - + peer2 = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); EXPECT_EQ(peer, peer2); - + peer2 = homa_peer_find(&self->peertab, 22222, &self->hsk.inet); EXPECT_NE(peer, peer2); - + EXPECT_EQ(2, homa_cores[cpu_number]->metrics.peer_new_entries); } @@ -92,7 +92,7 @@ TEST_F(homa_peertab, homa_peertab_init__vmalloc_failed) struct homa_peertab table; mock_vmalloc_errors = 1; EXPECT_EQ(ENOMEM, -homa_peertab_init(&table)); - + /* Make sure destroy is safe after failed init. */ homa_peertab_destroy(&table); } @@ -108,7 +108,7 @@ TEST_F(homa_peertab, homa_peertab_gc_dsts) mock_cycles = 100000000; homa_dst_refresh(&self->peertab, peer, &self->hsk); EXPECT_EQ(3, dead_count(&self->peertab)); - + homa_peertab_gc_dsts(&self->peertab, 150000000); EXPECT_EQ(2, dead_count(&self->peertab)); homa_peertab_gc_dsts(&self->peertab, ~0); @@ -118,7 +118,7 @@ TEST_F(homa_peertab, homa_peertab_gc_dsts) TEST_F(homa_peertab, homa_peer_find__conflicting_creates) { struct homa_peer *peer; - + test_data = self; mock_spin_lock_hook = peer_lock_hook; peer = homa_peer_find(&self->peertab, 444, &self->hsk.inet); @@ -128,21 +128,21 @@ TEST_F(homa_peertab, homa_peer_find__conflicting_creates) TEST_F(homa_peertab, homa_peer_find__kmalloc_error) { struct homa_peer *peer; - + mock_kmalloc_errors = 1; peer = homa_peer_find(&self->peertab, 444, &self->hsk.inet); EXPECT_EQ(ENOMEM, -PTR_ERR(peer)); - + EXPECT_EQ(1, homa_cores[cpu_number]->metrics.peer_kmalloc_errors); } TEST_F(homa_peertab, homa_peer_find__route_error) { struct homa_peer *peer; - + mock_route_errors = 1; peer = homa_peer_find(&self->peertab, 444, &self->hsk.inet); EXPECT_EQ(EHOSTUNREACH, -PTR_ERR(peer)); - + EXPECT_EQ(1, homa_cores[cpu_number]->metrics.peer_route_errors); } @@ -153,7 +153,7 @@ TEST_F(homa_peertab, homa_dst_refresh__basics) peer = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(11111, peer->addr); - + old_dst = homa_get_dst(peer, &self->hsk); homa_dst_refresh(&self->homa.peers, peer, &self->hsk); EXPECT_NE(old_dst, peer->dst); @@ -166,7 +166,7 @@ TEST_F(homa_peertab, homa_dst_refresh__routing_error) peer = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(11111, peer->addr); - + old_dst = homa_get_dst(peer, &self->hsk); mock_route_errors = 1; homa_dst_refresh(&self->homa.peers, peer, &self->hsk); @@ -181,7 +181,7 @@ TEST_F(homa_peertab, homa_dst_refresh__malloc_error) peer = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(11111, peer->addr); - + old_dst = homa_get_dst(peer, &self->hsk); mock_kmalloc_errors = 1; homa_dst_refresh(&self->homa.peers, peer, &self->hsk); @@ -194,7 +194,7 @@ TEST_F(homa_peertab, homa_dst_refresh__free_old_dsts) peer = homa_peer_find(&self->peertab, 11111, &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(11111, peer->addr); - + mock_cycles = 0; homa_dst_refresh(&self->homa.peers, peer, &self->hsk); homa_dst_refresh(&self->homa.peers, peer, &self->hsk); @@ -208,7 +208,7 @@ TEST_F(homa_peertab, homa_unsched_priority) { struct homa_peer peer; homa_peer_set_cutoffs(&peer, INT_MAX, 0, 0, INT_MAX, 200, 100, 0, 0); - + EXPECT_EQ(5, homa_unsched_priority(&self->homa, &peer, 10)); EXPECT_EQ(4, homa_unsched_priority(&self->homa, &peer, 200)); EXPECT_EQ(3, homa_unsched_priority(&self->homa, &peer, 201)); @@ -220,12 +220,12 @@ TEST_F(homa_peertab, homa_peer_lock_slow) struct homa_peer *peer = homa_peer_find(&self->peertab, 444, &self->hsk.inet); ASSERT_NE(NULL, peer); - + homa_peer_lock(peer); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.peer_lock_misses); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.peer_lock_miss_cycles); homa_peer_unlock(peer); - + mock_trylock_errors = 1; mock_spin_lock_hook = peer_spinlock_hook; homa_peer_lock(peer); @@ -248,7 +248,7 @@ TEST_F(homa_peertab, homa_peer_add_ack) 103, 100, 100); struct homa_peer *peer = crpc1->peer; EXPECT_EQ(0, peer->num_acks); - + /* Initialize 3 acks in the peer. */ peer->acks[0] = (struct homa_ack) { .client_port = htons(1000), @@ -263,19 +263,19 @@ TEST_F(homa_peertab, homa_peer_add_ack) .server_port = htons(self->server_port), .client_id = cpu_to_be64(92)}; peer->num_acks = 3; - + /* Add one RPC to unacked (fits). */ homa_peer_add_ack(crpc1); EXPECT_EQ(4, peer->num_acks); EXPECT_STREQ("client_port 32768, server_port 99, client_id 101", unit_ack_string(&peer->acks[3])); - + /* Add another RPC to unacked (also fits). */ homa_peer_add_ack(crpc2); EXPECT_EQ(5, peer->num_acks); EXPECT_STREQ("client_port 32768, server_port 99, client_id 102", unit_ack_string(&peer->acks[4])); - + /* Third RPC overflows, triggers ACK transmission. */ unit_log_clear(); mock_xmit_log_verbose = 1; @@ -294,11 +294,11 @@ TEST_F(homa_peertab, homa_peer_get_acks) &self->hsk.inet); ASSERT_NE(NULL, peer); EXPECT_EQ(0, peer->num_acks); - + // First call: nothing available. struct homa_ack acks[2]; EXPECT_EQ(0, homa_peer_get_acks(peer, 2, acks)); - + // Second call: retrieve 2 out of 3. peer->acks[0] = (struct homa_ack) { .client_port = htons(4000), @@ -319,7 +319,7 @@ TEST_F(homa_peertab, homa_peer_get_acks) EXPECT_STREQ("client_port 4002, server_port 5002, client_id 102", unit_ack_string(&acks[1])); EXPECT_EQ(1, peer->num_acks); - + // Third call: retrieve final id. EXPECT_EQ(1, homa_peer_get_acks(peer, 2, acks)); EXPECT_STREQ("client_port 4000, server_port 5000, client_id 100", diff --git a/test/unit_homa_plumbing.c b/test/unit_homa_plumbing.c index 2eab929f..58be23c5 100644 --- a/test/unit_homa_plumbing.c +++ b/test/unit_homa_plumbing.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -127,7 +127,7 @@ TEST_F(homa_plumbing, homa_ioc_recv__use_iovec) { unit_client_rpc(&self->hsk, RPC_READY, self->client_ip, self->server_ip, self->server_port, self->client_id, 100, 200); - + self->recv_args.buf = NULL; self->recv_args.iovec = self->recv_vec; self->recv_args.len = 2; @@ -145,7 +145,7 @@ TEST_F(homa_plumbing, homa_ioc_recv__error_in_import_iovec) { unit_client_rpc(&self->hsk, RPC_READY, self->client_ip, self->server_ip, self->server_port, self->client_id, 100, 200); - + self->recv_args.buf = NULL; self->recv_args.iovec = self->recv_vec; self->recv_args.len = 2; @@ -169,14 +169,14 @@ TEST_F(homa_plumbing, homa_ioc_recv__HOMA_RECV_PARTIAL) self->server_port, self->client_id, 100, 200); self->recv_args.flags = HOMA_RECV_NONBLOCKING|HOMA_RECV_RESPONSE |HOMA_RECV_PARTIAL; - + // First call gets most of message. self->recv_args.len = 150; EXPECT_EQ(150, homa_ioc_recv(&self->hsk.inet.sk, (unsigned long) &self->recv_args)); EXPECT_EQ(self->client_id, self->recv_args.actualId); EXPECT_EQ(1, unit_list_length(&self->hsk.active_rpcs)); - + // Second call gets remainder, deletes message. self->recv_args.len = 200; self->recv_args.source_addr.sin_addr.s_addr = 0; @@ -405,7 +405,7 @@ TEST_F(homa_plumbing, homa_softirq__basics) TEST_F(homa_plumbing, homa_softirq__reorder_incoming_packets) { struct sk_buff *skb, *skb2, *skb3, *skb4; - + self->data.common.sender_id = cpu_to_be64(2000); self->data.message_length = htonl(2000); skb = mock_skb_new(self->client_ip, &self->data.common, 1400, 0); @@ -429,7 +429,7 @@ TEST_F(homa_plumbing, homa_softirq__reorder_incoming_packets) TEST_F(homa_plumbing, homa_softirq__reorder_short_packet_at_front) { struct sk_buff *skb, *skb2, *skb3, *skb4; - + self->data.common.sender_id = cpu_to_be64(200); self->data.message_length = htonl(200); skb = mock_skb_new(self->client_ip, &self->data.common, 200, 0); @@ -453,7 +453,7 @@ TEST_F(homa_plumbing, homa_softirq__reorder_short_packet_at_front) TEST_F(homa_plumbing, homa_softirq__nothing_to_reorder) { struct sk_buff *skb, *skb2, *skb3; - + self->data.common.sender_id = cpu_to_be64(2000); self->data.message_length = htonl(2000); skb = mock_skb_new(self->client_ip, &self->data.common, 1400, 0); @@ -521,7 +521,7 @@ TEST_F(homa_plumbing, homa_softirq__multiple_packets_different_sockets) struct homa_sock sock2; mock_sock_init(&sock2, &self->homa, 0); homa_sock_bind(&self->homa.port_map, &sock2, self->server_port+1); - + skb = mock_skb_new(self->client_ip, &self->data.common, 1400, 1400); self->data.common.sender_id += 2; self->data.common.dport = htons(self->server_port+1); @@ -564,7 +564,7 @@ TEST_F(homa_plumbing, homa_metrics_open) { EXPECT_EQ(0, homa_metrics_open(NULL, NULL)); EXPECT_NE(NULL, self->homa.metrics); - + strcpy(self->homa.metrics, "12345"); EXPECT_EQ(0, homa_metrics_open(NULL, NULL)); EXPECT_EQ(5, strlen(self->homa.metrics)); @@ -581,12 +581,12 @@ TEST_F(homa_plumbing, homa_metrics_read__basics) EXPECT_EQ(5, homa_metrics_read(NULL, buffer, 5, &offset)); EXPECT_STREQ("_copy_to_user copied 5 bytes", unit_log_get()); EXPECT_EQ(15, offset); - + unit_log_clear(); EXPECT_EQ(11, homa_metrics_read(NULL, buffer, 1000, &offset)); EXPECT_STREQ("_copy_to_user copied 11 bytes", unit_log_get()); EXPECT_EQ(26, offset); - + unit_log_clear(); EXPECT_EQ(0, homa_metrics_read(NULL, buffer, 1000, &offset)); EXPECT_STREQ("", unit_log_get()); @@ -609,7 +609,7 @@ TEST_F(homa_plumbing, homa_metrics_release) self->homa.metrics_active_opens = 2; EXPECT_EQ(0, homa_metrics_release(NULL, NULL)); EXPECT_EQ(1, self->homa.metrics_active_opens); - + EXPECT_EQ(0, homa_metrics_release(NULL, NULL)); EXPECT_EQ(0, self->homa.metrics_active_opens); } diff --git a/test/unit_homa_socktab.c b/test/unit_homa_socktab.c index cd1916cc..a3617468 100644 --- a/test/unit_homa_socktab.c +++ b/test/unit_homa_socktab.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -132,19 +132,19 @@ TEST_F(homa_socktab, homa_sock_shutdown__basics) client2 = hsk2.port; mock_sock_init(&hsk3, &self->homa, 0); client3 = hsk3.port; - + EXPECT_EQ(&hsk2, homa_sock_find(&self->homa.port_map, client2)); EXPECT_EQ(&hsk2, homa_sock_find(&self->homa.port_map, 100)); EXPECT_EQ(&hsk3, homa_sock_find(&self->homa.port_map, client3)); - + homa_sock_shutdown(&hsk2); - + EXPECT_EQ(NULL, homa_sock_find(&self->homa.port_map, client2)); EXPECT_EQ(NULL, homa_sock_find(&self->homa.port_map, 100)); EXPECT_EQ(&hsk3, homa_sock_find(&self->homa.port_map, client3)); - + homa_sock_shutdown(&hsk3); - + EXPECT_EQ(NULL, homa_sock_find(&self->homa.port_map, client2)); EXPECT_EQ(NULL, homa_sock_find(&self->homa.port_map, 100)); EXPECT_EQ(NULL, homa_sock_find(&self->homa.port_map, client3)); @@ -201,20 +201,20 @@ TEST_F(homa_socktab, homa_sock_bind) struct homa_sock hsk2; mock_sock_init(&hsk2, &self->homa, 0); EXPECT_EQ(0, homa_sock_bind(&self->homa.port_map, &hsk2, 100)); - + EXPECT_EQ(0, -homa_sock_bind(&self->homa.port_map, &self->hsk, 0)); EXPECT_EQ(HOMA_MIN_DEFAULT_PORT, self->hsk.port); EXPECT_EQ(EINVAL, -homa_sock_bind(&self->homa.port_map, &self->hsk, HOMA_MIN_DEFAULT_PORT + 100)); - + EXPECT_EQ(EADDRINUSE, -homa_sock_bind(&self->homa.port_map, &self->hsk, 100)); EXPECT_EQ(0, -homa_sock_bind(&self->homa.port_map, &hsk2, 100)); - + EXPECT_EQ(0, -homa_sock_bind(&self->homa.port_map, &self->hsk, 110)); - + EXPECT_EQ(&self->hsk, homa_sock_find(&self->homa.port_map, 110)); EXPECT_EQ(0, -homa_sock_bind(&self->homa.port_map, &self->hsk, 120)); @@ -250,7 +250,7 @@ TEST_F(homa_socktab, homa_sock_find__long_hash_chain) mock_sock_init(&hsk4, &self->homa, 0); EXPECT_EQ(0, homa_sock_bind(&self->homa.port_map, &hsk4, 5*HOMA_SOCKTAB_BUCKETS + 13)); - + EXPECT_EQ(&self->hsk, homa_sock_find(&self->homa.port_map, 13)); EXPECT_EQ(&hsk2, homa_sock_find(&self->homa.port_map, @@ -259,7 +259,7 @@ TEST_F(homa_socktab, homa_sock_find__long_hash_chain) 3*HOMA_SOCKTAB_BUCKETS + 13)); EXPECT_EQ(&hsk4, homa_sock_find(&self->homa.port_map, 5*HOMA_SOCKTAB_BUCKETS + 13)); - + homa_sock_destroy(&hsk2); homa_sock_destroy(&hsk3); homa_sock_destroy(&hsk4); @@ -268,12 +268,12 @@ TEST_F(homa_socktab, homa_sock_find__long_hash_chain) TEST_F(homa_socktab, homa_sock_lock_slow) { mock_cycles = ~0; - + homa_sock_lock(&self->hsk, "unit test"); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.socket_lock_misses); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.socket_lock_miss_cycles); homa_sock_unlock(&self->hsk); - + mock_trylock_errors = 1; homa_sock_lock(&self->hsk, "unit test"); EXPECT_EQ(1, homa_cores[cpu_number]->metrics.socket_lock_misses); diff --git a/test/unit_homa_timer.c b/test/unit_homa_timer.c index 801f5245..4d5cd1f4 100644 --- a/test/unit_homa_timer.c +++ b/test/unit_homa_timer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -62,25 +62,25 @@ TEST_F(homa_timer, homa_check_timeout__request_ack) self->server_id, 100, 100); ASSERT_NE(NULL, srpc); self->homa.request_ack_ticks = 2; - + /* First call: do nothing (response not fully transmitted). */ homa_check_rpc(srpc); EXPECT_EQ(0, srpc->done_timer_ticks); - + /* Second call: set done_timer_ticks. */ homa_xmit_data(srpc, false); unit_log_clear(); homa_check_rpc(srpc); EXPECT_EQ(100, srpc->done_timer_ticks); EXPECT_STREQ("", unit_log_get()); - + /* Third call: haven't hit request_ack_ticks yet. */ unit_log_clear(); self->homa.timer_ticks++; homa_check_rpc(srpc); EXPECT_EQ(100, srpc->done_timer_ticks); EXPECT_STREQ("", unit_log_get()); - + /* Fourth call: request ack. */ unit_log_clear(); self->homa.timer_ticks++; @@ -135,13 +135,13 @@ TEST_F(homa_timer, homa_check_timeout__resend_ticks_not_reached) self->homa.resend_ticks = 3; crpc->msgout.granted = 0; crpc->peer->outstanding_resends = self->homa.timeout_resends + 10; - + /* First call: resend_ticks-1 not reached. */ crpc->silent_ticks = 1; EXPECT_EQ(0, homa_check_rpc(crpc)); EXPECT_EQ(1, crpc->silent_ticks); EXPECT_STREQ("", unit_log_get()); - + /* Second call: resend_ticks-1 reached. */ crpc->silent_ticks = 2; EXPECT_EQ(1, homa_check_rpc(crpc)); @@ -287,13 +287,13 @@ TEST_F(homa_timer, homa_check_timeout__send_resend) srpc->silent_ticks = self->homa.resend_ticks-1; srpc->resend_timer_ticks = self->homa.timer_ticks - 10; srpc->peer->resend_rpc = srpc; - + /* First call: no resend, but choose this RPC for least_recent_rpc. */ EXPECT_EQ(0, homa_check_rpc(srpc)); EXPECT_STREQ("", unit_log_get()); EXPECT_EQ(0, srpc->peer->outstanding_resends); EXPECT_EQ(srpc, srpc->peer->least_recent_rpc); - + /* Second call: issue resend. */ self->homa.timer_ticks++; srpc->silent_ticks++; @@ -328,7 +328,7 @@ TEST_F(homa_timer, homa_timer__basics) homa_timer(&self->homa); EXPECT_EQ(3, crpc->silent_ticks); EXPECT_STREQ("", unit_log_get()); - + /* Timeout the peer. */ unit_log_clear(); crpc->peer->outstanding_resends = self->homa.timeout_resends; @@ -345,12 +345,12 @@ TEST_F(homa_timer, homa_timer__reap_dead_rpcs) ASSERT_NE(NULL, dead); homa_rpc_free(dead); EXPECT_EQ(30, self->hsk.dead_skbs); - + // First call to homa_timer: not enough dead skbs. self->homa.dead_buffs_limit = 31; homa_timer(&self->homa); EXPECT_EQ(30, self->hsk.dead_skbs); - + // Second call to homa_timer: must reap. self->homa.dead_buffs_limit = 15; homa_timer(&self->homa); diff --git a/test/unit_homa_utils.c b/test/unit_homa_utils.c index f7cef96f..d7a83611 100644 --- a/test/unit_homa_utils.c +++ b/test/unit_homa_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -84,7 +84,7 @@ FIXTURE_TEARDOWN(homa_utils) * @c6: New value for homa->unsched_cutoffs[6] * @c7: New value for homa->unsched_cutoffs[7] */ -static void set_cutoffs(struct homa *homa, int c0, int c1, int c2, +static void set_cutoffs(struct homa *homa, int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7) { homa->unsched_cutoffs[0] = c0; @@ -100,7 +100,7 @@ static void set_cutoffs(struct homa *homa, int c0, int c1, int c2, /** * dead_rpcs() - Logs the ids for all of the RPCS in hsk->dead_rpcs. * @hsk: Homa socket to check for dead RPCs. - * + * * Return: the contents of the unit test log. */ static const char *dead_rpcs(struct homa_sock *hsk) @@ -229,7 +229,7 @@ TEST_F(homa_utils, homa_rpc_lock_slow) ASSERT_FALSE(IS_ERR(srpc)); list_add_tail_rcu(&srpc->active_links, &srpc->hsk->active_rpcs); homa_rpc_unlock(srpc); - + EXPECT_EQ(0, homa_cores[cpu_number]->metrics.client_lock_misses); EXPECT_EQ(0, homa_cores[cpu_number]->metrics.client_lock_miss_cycles); homa_rpc_lock_slow(crpc); @@ -242,7 +242,7 @@ TEST_F(homa_utils, homa_rpc_lock_slow) homa_rpc_unlock(srpc); EXPECT_EQ(1, homa_cores[cpu_number]->metrics.server_lock_misses); EXPECT_NE(0, homa_cores[cpu_number]->metrics.server_lock_miss_cycles); - + } TEST_F(homa_utils, homa_rpc_acked__basics) @@ -258,7 +258,7 @@ TEST_F(homa_utils, homa_rpc_acked__basics) .client_id = cpu_to_be64(self->client_id)}; homa_rpc_acked(&hsk, self->client_ip, &ack); EXPECT_EQ(0, unit_list_length(&hsk.active_rpcs)); - EXPECT_STREQ("DEAD", homa_symbol_for_state(srpc)); + EXPECT_STREQ("DEAD", homa_symbol_for_state(srpc)); } TEST_F(homa_utils, homa_rpc_acked__lookup_socket) { @@ -273,7 +273,7 @@ TEST_F(homa_utils, homa_rpc_acked__lookup_socket) .client_id = cpu_to_be64(self->client_id)}; homa_rpc_acked(&self->hsk, self->client_ip, &ack); EXPECT_EQ(0, unit_list_length(&hsk.active_rpcs)); - EXPECT_STREQ("DEAD", homa_symbol_for_state(srpc)); + EXPECT_STREQ("DEAD", homa_symbol_for_state(srpc)); } TEST_F(homa_utils, homa_rpc_acked__no_such_socket) { @@ -288,7 +288,7 @@ TEST_F(homa_utils, homa_rpc_acked__no_such_socket) .client_id = cpu_to_be64(self->client_id)}; homa_rpc_acked(&hsk, self->client_ip, &ack); EXPECT_EQ(1, unit_list_length(&hsk.active_rpcs)); - EXPECT_STREQ("OUTGOING", homa_symbol_for_state(srpc)); + EXPECT_STREQ("OUTGOING", homa_symbol_for_state(srpc)); } TEST_F(homa_utils, homa_rpc_acked__no_such_rpc) { @@ -302,7 +302,7 @@ TEST_F(homa_utils, homa_rpc_acked__no_such_rpc) .server_port = htons(self->server_port), .client_id = cpu_to_be64(self->client_id+10)}; homa_rpc_acked(&hsk, self->client_ip, &ack); - EXPECT_EQ(1, unit_list_length(&hsk.active_rpcs)); + EXPECT_EQ(1, unit_list_length(&hsk.active_rpcs)); EXPECT_STREQ("OUTGOING", homa_symbol_for_state(srpc)); } @@ -633,12 +633,12 @@ TEST_F(homa_utils, homa_print_ipv4_addr) { char *p1, *p2; int i; - + p1 = homa_print_ipv4_addr(unit_get_in_addr("192.168.0.1")); p2 = homa_print_ipv4_addr(htonl((1<<24) + (2<<16) + (3<<8) + 4)); EXPECT_STREQ("192.168.0.1", p1); EXPECT_STREQ("1.2.3.4", p2); - + /* Make sure buffers eventually did reused. */ for (i = 0; i < 20; i++) homa_print_ipv4_addr(unit_get_in_addr("5.6.7.8")); @@ -653,13 +653,13 @@ TEST_F(homa_utils, homa_snprintf) "Test message with values: %d and %d", 100, 1000); EXPECT_EQ(38, used); EXPECT_STREQ("Test message with values: 100 and 1000", buffer); - + used = homa_snprintf(buffer, sizeof32(buffer), used, "; plus: %d", 123456); EXPECT_EQ(49, used); EXPECT_STREQ("Test message with values: 100 and 1000; plus: 123", buffer); - + used = homa_snprintf(buffer, sizeof32(buffer), used, "more text, none of which fits"); EXPECT_EQ(49, used); @@ -673,12 +673,12 @@ TEST_F(homa_utils, homa_append_metric) homa_append_metric(&self->homa, "x: %d, y: %d", 10, 20); EXPECT_EQ(12, self->homa.metrics_length); EXPECT_STREQ("x: 10, y: 20", self->homa.metrics); - + homa_append_metric(&self->homa, ", z: %d", 12345); EXPECT_EQ(22, self->homa.metrics_length); EXPECT_STREQ("x: 10, y: 20, z: 12345", self->homa.metrics); EXPECT_EQ(30, self->homa.metrics_capacity); - + homa_append_metric(&self->homa, ", q: %050d", 88); EXPECT_EQ(77, self->homa.metrics_length); EXPECT_STREQ("x: 10, y: 20, z: 12345, " diff --git a/test/unit_timetrace.c b/test/unit_timetrace.c index 43121715..13187a6d 100644 --- a/test/unit_timetrace.c +++ b/test/unit_timetrace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -113,24 +113,24 @@ TEST_F(timetrace, tt_proc_open__compute_start_time_and_skip_events) { char buffer[1000]; tt_buffer_size = 4; - + tt_record_buf(tt_buffers[0], 1500, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[0], 1600, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[0], 1700, "Buf0", 0, 0, 0, 0); - + tt_record_buf(tt_buffers[1], 1000, "Buf1", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1100, "Buf1", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1200, "Buf1", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1300, "Buf1", 0, 0, 0, 0); - + tt_record_buf(tt_buffers[2], 1100, "Buf2", 0, 0, 0, 0); tt_record_buf(tt_buffers[2], 1150, "Buf2", 0, 0, 0, 0); tt_record_buf(tt_buffers[2], 1160, "Buf2", 0, 0, 0, 0); tt_record_buf(tt_buffers[2], 1210, "Buf2", 0, 0, 0, 0); - + tt_record_buf(tt_buffers[3], 1000, "Buf3", 0, 0, 0, 0); tt_record_buf(tt_buffers[3], 1400, "Buf3", 0, 0, 0, 0); - + tt_proc_open(NULL, &self->file); tt_proc_read(&self->file, buffer, sizeof(buffer), 0); tt_proc_release(NULL, &self->file); @@ -212,7 +212,7 @@ TEST_F(timetrace, tt_proc_read__sort_events_by_time) tt_record_buf(tt_buffers[3], 1600, "Buf3", 0, 0, 0, 0); tt_record_buf(tt_buffers[0], 1700, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1800, "Buf1", 0, 0, 0, 0); - + tt_proc_open(NULL, &self->file); tt_proc_read(&self->file, buffer, sizeof(buffer), 0); tt_proc_release(NULL, &self->file); @@ -269,14 +269,14 @@ TEST_F(timetrace, tt_proc_release__bogus_file) TEST_F(timetrace, tt_proc_release__unfreeze) { struct file file2; - + tt_buffer_size = 4; tt_record_buf(tt_buffers[1], 1000, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1100, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1200, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1300, "Buf0", 0, 0, 0, 0); tt_record_buf(tt_buffers[1], 1400, "Buf0", 0, 0, 0, 0); - + tt_freeze(); tt_proc_open(NULL, &self->file); EXPECT_EQ(2, tt_freeze_count.counter); @@ -284,13 +284,13 @@ TEST_F(timetrace, tt_proc_release__unfreeze) tt_proc_open(NULL, &file2); EXPECT_EQ(3, tt_freeze_count.counter); EXPECT_TRUE(tt_frozen); - + tt_proc_release(NULL, &self->file); EXPECT_EQ(2, tt_freeze_count.counter); EXPECT_TRUE(tt_frozen); EXPECT_NE(NULL, tt_buffers[1]->events[3].format); EXPECT_EQ(2, tt_buffers[1]->next_index); - + tt_proc_release(NULL, &file2); EXPECT_EQ(0, tt_freeze_count.counter); EXPECT_FALSE(tt_frozen); diff --git a/test/utils.c b/test/utils.c index fd9de88c..2df2c3bf 100644 --- a/test/utils.c +++ b/test/utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/test/utils.h b/test/utils.h index 35ff486c..fb699e77 100644 --- a/test/utils.h +++ b/test/utils.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2020 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/timetrace.c b/timetrace.c index 9ad36ec9..e4560f8f 100644 --- a/timetrace.c +++ b/timetrace.c @@ -32,7 +32,7 @@ extern int tt_linux_homa_temp_default[]; extern void tt_inc_metric(int metric, __u64 count); extern void (*tt_linux_inc_metrics)(int metric, __u64 count); extern void tt_linux_skip_metrics(int metric, __u64 count); -extern void homa_trace(__u64 u0, __u64 u1, int i0, int i1); +extern void homa_trace(__u64 u0, __u64 u1, int i0, int i1); #endif /* Separate buffers for each core: this eliminates the need for @@ -95,14 +95,14 @@ bool tt_test_no_khz = false; * @temp: Pointer to homa's "temp" configuration parameters, which * we should make available to the kernel. NULL means no * such variables available. - * + * * Return : 0 means success, anything else means an error occurred (a * log message will be printed to describe the error). */ int tt_init(char *proc_file, int *temp) { int i; - + if (init) { return 0; } @@ -118,19 +118,19 @@ int tt_init(char *proc_file, int *temp) memset(buffer, 0, sizeof(*buffer)); tt_buffers[i] = buffer; } - + tt_dir_entry = proc_create(proc_file, S_IRUGO, NULL, &tt_pops); if (!tt_dir_entry) { printk(KERN_ERR "couldn't create /proc/%s for timetrace " "reading\n", proc_file); goto error; } - + spin_lock_init(&tt_lock); tt_freeze_count.counter = 0; tt_frozen = false; init = true; - + #ifdef TT_KERNEL for (i = 0; i < nr_cpu_ids; i++) { tt_linux_buffers[i] = tt_buffers[i]; @@ -141,9 +141,9 @@ int tt_init(char *proc_file, int *temp) if (temp) tt_linux_homa_temp = temp; #endif - + return 0; - + error: for (i = 0; i < nr_cpu_ids; i++) { kfree(tt_buffers[i]); @@ -169,7 +169,7 @@ void tt_destroy(void) tt_buffers[i] = NULL; } tt_freeze_count.counter = 1; - + #ifdef TT_KERNEL tt_linux_freeze_count = &tt_linux_freeze_no_homa; for (i = 0; i < nr_cpu_ids; i++) { @@ -182,7 +182,7 @@ void tt_destroy(void) } tt_linux_homa_temp = tt_linux_homa_temp_default; #endif - + spin_unlock(&tt_lock); } @@ -257,7 +257,7 @@ void tt_record_buf(struct tt_buffer *buffer, __u64 timestamp, * opened to read timetrace info. * @inode: The inode corresponding to the file. * @file: Information about the open file. - * + * * Return: 0 for success, else a negative errno. */ int tt_proc_open(struct inode *inode, struct file *file) @@ -267,7 +267,7 @@ int tt_proc_open(struct inode *inode, struct file *file) __u64 start_time; int result = 0; int i; - + spin_lock(&tt_lock); if (!init) { result = -EINVAL; @@ -281,15 +281,15 @@ int tt_proc_open(struct inode *inode, struct file *file) pf->file = file; pf->bytes_available = 0; pf->next_byte = pf->msg_storage; - + atomic_inc(&tt_freeze_count); - + /* Find the oldest event in each trace. This will be events[0] * if we never completely filled the buffer, otherwise * events[nextIndex+1]. This means we don't print the entry at * nextIndex; this is convenient because it simplifies boundary * conditions in the code below. - * + * * At the same time, find the most recent "oldest time" from * any buffer that has wrapped around (data from earlier than * this isn't necessarily complete, since there may have been @@ -310,9 +310,9 @@ int tt_proc_open(struct inode *inode, struct file *file) } } } - + /* Skip over all events before start_time, in order to make - * sure that there's no missing data in what we print. + * sure that there's no missing data in what we print. */ for (i = 0; i < nr_cpu_ids; i++) { buffer = tt_buffers[i]; @@ -321,14 +321,14 @@ int tt_proc_open(struct inode *inode, struct file *file) pf->pos[i] = (pf->pos[i] + 1) & (tt_buffer_size-1); } } - + file->private_data = pf; - + if (!tt_test_no_khz) { pf->bytes_available = snprintf(pf->msg_storage, TT_PF_BUF_SIZE, "cpu_khz: %u\n", cpu_khz); } - + done: spin_unlock(&tt_lock); return result; @@ -349,13 +349,13 @@ int tt_proc_open(struct inode *inode, struct file *file) */ ssize_t tt_proc_read(struct file *file, char __user *user_buf, size_t length, loff_t *offset) -{ +{ /* # bytes of data that have accumulated in pf->msg_storage but * haven't been copied to user space yet. */ int copied_to_user = 0; struct tt_proc_file *pf = file->private_data; - + spin_lock(&tt_lock); if ((pf == NULL) || (pf->file != file)) { printk(KERN_ERR "tt_metrics_read found damaged " @@ -363,10 +363,10 @@ ssize_t tt_proc_read(struct file *file, char __user *user_buf, copied_to_user = -EINVAL; goto done; } - + if (!init) goto done; - + /* Each iteration through this loop processes one event (the one * with the earliest timestamp). We buffer data until pf->msg_storage * is full, then copy to user space and repeat. @@ -391,7 +391,7 @@ ssize_t tt_proc_read(struct file *file, char __user *user_buf, /* None of the traces have any more events to process. */ goto flush; } - + /* Format one event. */ event = &(tt_buffers[current_core]->events[ pf->pos[current_core]]); @@ -426,7 +426,7 @@ ssize_t tt_proc_read(struct file *file, char __user *user_buf, pf->pos[current_core] = (pf->pos[current_core] + 1) & (tt_buffer_size-1); continue; - + flush: chunk_size = pf->bytes_available; if (chunk_size > (length - copied_to_user)) { @@ -449,7 +449,7 @@ ssize_t tt_proc_read(struct file *file, char __user *user_buf, goto done; } } - + done: spin_unlock(&tt_lock); return copied_to_user; @@ -474,25 +474,25 @@ loff_t tt_proc_lseek(struct file *file, loff_t offset, int whence) * an open /proc/timetrace is closed. It performs cleanup. * @inode: The inode corresponding to the file. * @file: Information about the open file. - * - * Return: 0 for success, or a negative errno if there was an error. + * + * Return: 0 for success, or a negative errno if there was an error. */ int tt_proc_release(struct inode *inode, struct file *file) { int i; - + struct tt_proc_file *pf = file->private_data; if ((pf == NULL) || (pf->file != file)) { printk(KERN_ERR "tt_metrics_release found damaged " "private_data: 0x%p\n", file->private_data); return -EINVAL; } - + kfree(pf); file->private_data = NULL; - + spin_lock(&tt_lock); - + if (init) { if (tt_frozen && (atomic_read(&tt_freeze_count) == 2)) { atomic_dec(&tt_freeze_count); @@ -511,7 +511,7 @@ int tt_proc_release(struct inode *inode, struct file *file) } atomic_dec(&tt_freeze_count); } - + spin_unlock(&tt_lock); return 0; } diff --git a/timetrace.h b/timetrace.h index d2e5133b..61c10665 100644 --- a/timetrace.h +++ b/timetrace.h @@ -45,7 +45,7 @@ struct tt_event { * entry has never been occupied. */ const char* format; - + /** * Up to 4 additional arguments that may be referenced by * @format when printing out this event. diff --git a/util/Makefile b/util/Makefile index 85236d02..cde339a8 100644 --- a/util/Makefile +++ b/util/Makefile @@ -7,30 +7,30 @@ BINS := buffer_client buffer_server cp_node get_time_trace \ test_time_trace use_memory OBJS := $(patsubst %,%.o,$(BINS)) - + LIB_SRCS := dist.cc homa_api.c test_utils.cc time_trace.cc LIB_OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(LIB_SRCS))) - + .SECONDARY: $(OBJS) $(LIB_OBJS) all: $(BINS) - + cp_node: cp_node.o dist.o time_trace.o $(LIB_OBJS) g++ $(CFLAGS) $^ -lpthread -o $@ # This seems to be the only way to disable the built-in implicit rules # for %:%.c and %:%.cc. .SUFFIXES: - + %: %.o $(LIB_OBJS) g++ $(CFLAGS) $^ -lpthread -o $@ - + %.o: %.cc test_utils.h ../homa.h g++ -c $(CFLAGS) -std=c++17 $< -o $@ - + %.o: %.c test_utils.h ../homa.h cc -c $(CFLAGS) $< -o $@ - + homa_api.o: ../homa_api.c cc -c $(CFLAGS) $< -o $@ @@ -41,4 +41,3 @@ clean: # prints the value of a make variable. print-%: @echo $* = $($*) - \ No newline at end of file diff --git a/util/buffer_client.c b/util/buffer_client.c index 4c2d538d..20d809e8 100644 --- a/util/buffer_client.c +++ b/util/buffer_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,7 +41,7 @@ int main(int argc, char** argv) { #define BUFFER_SIZE 4096 char buffer[BUFFER_SIZE]; int bytesSent; - + if (argc < 3) { printf("Usage: %s hostName port\n", argv[0]); exit(1); @@ -53,7 +53,7 @@ int main(int argc, char** argv) { argv[2]); exit(1); } - + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; @@ -63,7 +63,7 @@ int main(int argc, char** argv) { host, gai_strerror(status)); exit(1); } - + while (1) { fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { diff --git a/util/buffer_server.c b/util/buffer_server.c index 5c51086b..874adc9c 100644 --- a/util/buffer_server.c +++ b/util/buffer_server.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,7 +35,7 @@ int main(int argc, char** argv) { int fd, port; int optval = 1; struct sockaddr_in bindAddress; - + if (argc < 2) { printf("Usage: %s port\n", argv[0]); exit(1); @@ -46,7 +46,7 @@ int main(int argc, char** argv) { argv[1]); exit(1); } - + fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { printf("Couldn't create socket: %s\n", strerror(errno)); @@ -69,7 +69,7 @@ int main(int argc, char** argv) { printf("Listen failed on socket: %s\n", strerror(errno)); exit(1); } - + while (1) { int peerFd; peerFd = accept(fd, NULL, NULL); diff --git a/util/cp_basic b/util/cp_basic index 590dfae5..8f4d4caa 100755 --- a/util/cp_basic +++ b/util/cp_basic @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cp_client_threads b/util/cp_client_threads index cca61eab..d137e7fb 100755 --- a/util/cp_client_threads +++ b/util/cp_client_threads @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -76,7 +76,7 @@ for workload in workloads: raise Error("No client RPC throughput found for experiment %s" % (exp)) tput[workload].append(sum(readings)/len(readings)) - + # print(tput) fig, (ax1, ax2) = plt.subplots(2, figsize=[4, 5]) fig.suptitle("%s Single-Client Throughput" % (options.protocol.capitalize()), diff --git a/util/cp_config b/util/cp_config index b99cefc2..945f5789 100755 --- a/util/cp_config +++ b/util/cp_config @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -179,7 +179,7 @@ if not options.plot_only: run_experiment(exp_name, clients, o) except Exception as e: log(traceback.format_exc()) - + for name, value in old_values.items(): print("Restoring %s to %s" % (name, value)) set_sysctl_parameter(name, value, range(0, options.num_nodes)) diff --git a/util/cp_load b/util/cp_load index a7e5a762..597e53b4 100755 --- a/util/cp_load +++ b/util/cp_load @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cp_mtu b/util/cp_mtu index ac55559a..36d5e9b5 100755 --- a/util/cp_mtu +++ b/util/cp_mtu @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cp_node.cc b/util/cp_node.cc index fbd18ffb..00fe8d6a 100644 --- a/util/cp_node.cc +++ b/util/cp_node.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2021 Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -97,29 +97,29 @@ struct conn_id { * This will be the low byte returned by int(). */ uint8_t client_port; - + /** @client: the node index for the client (starts from zero). */ uint8_t client; - + /** * @server_port: the index (starting at 0) of a particular port * within the server. */ uint8_t server_port; - + /** @server: the node index for the server (starts from 0). */ uint8_t server; - + conn_id(uint8_t server, uint8_t server_port, uint8_t client, uint8_t client_port) : client_port(client_port), client(client), server_port(server_port), server(server) {} - + conn_id() : client_port(0), client(0), server_port(0), server(0) {} - + inline operator int() { return *(reinterpret_cast(this)); @@ -371,7 +371,7 @@ int parse(std::vector &words, unsigned i, ValueType *value, { ValueType num; char *end; - + if (i >= words.size()) { printf("No value provided for %s\n", option); return 0; @@ -443,16 +443,16 @@ struct message_header { * header. */ int length:31; - + /** @freeze: true means the recipient should freeze its time trace. */ unsigned int freeze:1; - + /** * @cid: uniquely identifies the connection between a client * and a server. */ conn_id cid; - + /** * @msg_id: unique identifier for this message among all those * from a given client machine. @@ -530,12 +530,12 @@ class spin_lock { } } while (mutex->exchange(1, std::memory_order_acquire)); } - + ~spin_lock() { mutex->store(0, std::memory_order_release); } - + protected: std::atomic_bool *mutex; }; @@ -556,60 +556,60 @@ class tcp_connection { bool send_message(message_header *header); void set_epoll_events(int epoll_fd, uint32_t events); bool xmit(); - + /** @fd: File descriptor to use for reading and writing data. */ int fd; - + /** * @epoll_id: identifier for this connection, which will be stored * in the u32 field of the data for epoll events for this * connection. */ uint32_t epoll_id; - + /** * @port: Port number associated with this connection (listen port * for servers, outgoing port for clients). Used for error messages. */ int port; - + /** * @peer: Address of the machine on the other end of this connection. */ struct sockaddr_in peer; - + /** * @bytes_received: nonzero means we have read part of an incoming * request; the value indicates how many bytes have been received * so far. */ int bytes_received; - + /** * @header: will eventually hold the first bytes of an incoming * message. If @bytes_received is less than the size of this value, * then it has not yet been fully read. */ message_header header; - + /** * @outgoing: queue of headers for messages waiting to be * transmitted. The first entry may have been partially transmitted. */ std::deque outgoing; - + /* * @bytes_sent: Nonzero means we have sent part of the first message * in outgoing; the value indicates how many bytes have been * successfully transmitted. */ int bytes_sent; - + /** * @epoll_events: OR-ed combination of epoll events such as EPOLLIN * currently enabled for this connection. */ uint32_t epoll_events; - + /** * @error_message: holds human-readable error information after * an error. @@ -668,7 +668,7 @@ int tcp_connection::read(bool loop, { char buffer[100000]; char *next; - + while (1) { int count = ::read(fd, buffer, sizeof(buffer)); if (count <= 0) { @@ -705,9 +705,9 @@ int tcp_connection::read(bool loop, "port %d (fd %d) to %s: %s", port, fd, print_address(&peer), strerror(errno)); return 1; - + } - + /* * Process incoming bytes (could contains parts of multiple * requests). The first 4 bytes of each request give its @@ -773,7 +773,7 @@ int tcp_connection::read(bool loop, void tcp_connection::set_epoll_events(int epoll_fd, uint32_t events) { struct epoll_event ev; - + if (events == epoll_events) return; ev.events = events; @@ -822,7 +822,7 @@ bool tcp_connection::xmit() int start; int send_length; ssize_t result; - + while (true) { if (outgoing.size() == 0) return true; @@ -876,13 +876,13 @@ class server_metrics { public: /** @requests: Total number of requests handled so far. */ uint64_t requests; - + /** * @data: Total number of bytes of data in requests handled * so far. */ uint64_t data; - + server_metrics() :requests(0), data(0) {} }; @@ -899,22 +899,22 @@ class homa_server { homa_server(int port, int id); ~homa_server(); void server(); - + /** @id: Identifying number of this server. */ int id; - + /** @fd: File descriptor for Homa socket. */ int fd; - + /** * @buffer: Used for receiving requests and sending responses; * malloced, size HOMA_MAX_MESSAGE_LENGTH */ char *buffer; - + /** @metrics: Performance statistics. */ server_metrics metrics; - + /** @thread: Background thread that services requests. */ std::thread thread; }; @@ -960,13 +960,13 @@ void homa_server::server(void) size_t source_length; int length; char thread_name[50]; - + snprintf(thread_name, sizeof(thread_name), "S%d", id); time_trace::thread_buffer thread_buffer(thread_name); while (1) { uint64_t id = 0; int result; - + while (1) { source_length = sizeof(source); if (server_iovec) { @@ -1036,25 +1036,25 @@ class tcp_server { void accept(int epoll_fd); void read(int fd, int pid); void server(int thread_id); - + /** * @mutex: For synchronizing access to server-wide state, such * as listen_fd. */ std::atomic_bool mutex; - + /** @port: Port on which we listen for connections. */ int port; - + /** @id: Unique identifier for this server. */ int id; - + /** @listen_fd: File descriptor for the listen socket. */ int listen_fd; - + /** @epoll_fd: File descriptor used for epolling. */ int epoll_fd; - + /** * @epollet: EPOLLET if this flag should be used, or 0 otherwise. * We only use edge triggering if there are multiple receiving @@ -1062,22 +1062,22 @@ class tcp_server { * it's faster not to use it). */ int epollet; - + /** * @connections: Entry i contains information for a client * connection on fd i, or NULL if no such connection. */ tcp_connection *connections[MAX_FDS]; - + /** @metrics: Performance statistics. */ server_metrics metrics; - + /** * @thread: Background threads that both accept connections and * service requests on them. */ std::vector threads; - + /** @stop: True means that background threads should exit. */ bool stop; }; @@ -1141,7 +1141,7 @@ tcp_server::tcp_server(int port, int id, int num_threads) strerror(errno)); exit(1); } - + epoll_fd = epoll_create(10); if (epoll_fd < 0) { log(NORMAL, "FATAL: couldn't create epoll instance for " @@ -1157,7 +1157,7 @@ tcp_server::tcp_server(int port, int id, int num_threads) strerror(errno)); exit(1); } - + for (int i = 0; i < num_threads; i++) threads.emplace_back(&tcp_server::server, this, i); kfreeze_count = 0; @@ -1170,9 +1170,9 @@ tcp_server::tcp_server(int port, int id, int num_threads) tcp_server::~tcp_server() { int fds[2]; - + stop = true; - + /* In order to wake up the background threads, open a file that is * readable and add it to the epoll set. */ @@ -1190,7 +1190,7 @@ tcp_server::~tcp_server() strerror(errno)); exit(1); } - + for (size_t i = 0; i < threads.size(); i++) threads[i].join(); close(listen_fd); @@ -1224,17 +1224,17 @@ tcp_server::~tcp_server() void tcp_server::server(int thread_id) { char thread_name[50]; - + snprintf(thread_name, sizeof(thread_name), "S%d.%d", id, thread_id); time_trace::thread_buffer thread_buffer(thread_name); int pid = syscall(__NR_gettid); - + /* Each iteration through this loop processes a batch of epoll events. */ while (1) { #define MAX_EVENTS 20 struct epoll_event events[MAX_EVENTS]; int num_events; - + while (1) { num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (stop) @@ -1281,7 +1281,7 @@ void tcp_server::accept(int epoll_fd) int fd; struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); - + fd = ::accept4(listen_fd, reinterpret_cast(&client_addr), &addr_len, SOCK_NONBLOCK); if (fd < 0) { @@ -1351,7 +1351,7 @@ void tcp_server::read(int fd, int pid) /** * class client - Holds information that is common to both Homa clients - * and TCP clients. + * and TCP clients. */ class client { public: @@ -1368,38 +1368,38 @@ class client { * a response hasn't yet been received. */ bool active; - + rinfo() : start_time(0), active(false) {} }; - + client(int id); virtual ~client(); void check_completion(const char *protocol); int get_rinfo(); void record(uint64_t end_time, message_header *header); virtual void stop_sender(void) {} - + /** * @id: unique identifier for this client (index starting at * 0 for the first client. */ int id; - + /** * @rinfos: storage for more than enough rinfos to handle all of the * outstanding requests. */ std::vector rinfos; - + /** @last_rinfo: index into rinfos of last slot that was allocated. */ int last_rinfo; - + /** * @receivers_running: number of receiving threads that have * initialized and are ready to receive responses. */ std::atomic receivers_running; - + /** * @request_servers: a randomly chosen collection of indexes into * server_addrs; used to select the server for each outgoing request. @@ -1411,7 +1411,7 @@ class client { * the next outgoing RPC. */ uint32_t next_server; - + /** * @request_lengths: a randomly chosen collection of lengths to * use for outgoing RPCs. Precomputed to save time during the @@ -1426,7 +1426,7 @@ class client { * the next outgoing RPC. */ uint32_t next_length; - + /** * @request_intervals: a randomly chosen collection of inter-request * intervals, measured in rdtsc cycles. Precomputed to save time @@ -1441,13 +1441,13 @@ class client { * for the next outgoing RPC. */ std::atomic next_interval; - + /** * @actual_lengths: a circular buffer that holds the actual payload * sizes used for the most recent RPCs. */ std::vector actual_lengths; - + /** * @actual_rtts: a circular buffer that holds the actual round trip * times (measured in rdtsc cycles) for the most recent RPCs. Entries @@ -1460,43 +1460,43 @@ class client { * and actual_rtts. */ #define NUM_CLIENT_STATS 500000 - + /** @requests: total number of RPCs issued so far for each server. */ std::vector requests; - + /** @responses: total number of responses received so far from * each server. Dynamically allocated (as of 3/2020, can't use * vector with std::atomic). */ std::atomic *responses; - + /** @num_servers: Number of entries in @responses. */ size_t num_servers; - + /** * @total_requests: total number of RPCs issued so far across all * servers. */ uint64_t total_requests; - + /** * @total_responses: total number of responses received so far from all * servers. */ std::atomic total_responses; - + /** * @response_data: total number of bytes of data in responses * received so far. */ std::atomic response_data; - + /** * @total_rtt: sum of round-trip times (in rdtsc cycles) for * all responses received so far. */ std::atomic total_rtt; - + /** * @lag: time in rdtsc cycles by which we are running behind * because client_port_max was exceeded (i.e., the request @@ -1507,7 +1507,7 @@ class client { /** @clients: keeps track of all existing clients. */ std::vector clients; - + /** * client::client() - Constructor for client objects. * @@ -1536,7 +1536,7 @@ client::client(int id) , lag(0) { rinfos.resize(2*client_port_max + 5); - + /* Precompute information about the requests this client will * generate. Pick a different prime number for the size of each * vector, so that they will wrap at different times, giving @@ -1625,12 +1625,12 @@ void client::check_completion(const char *protocol) /** * get_rinfo() - Find an available rinfo slot and return its index in - * rinfos. + * rinfos. */ int client::get_rinfo() { int next = last_rinfo; - + while (true) { next++; if (next >= static_cast(rinfos.size())) @@ -1661,7 +1661,7 @@ void client::record(uint64_t end_time, message_header *header) int server_id; int slot = total_responses.fetch_add(1) % NUM_CLIENT_STATS; int64_t rtt; - + if (header->msg_id >= rinfos.size()) { log(NORMAL, "ERROR: msg_id (%u) exceed rinfos.size (%lu)\n", header->msg_id, rinfos.size()); @@ -1675,7 +1675,7 @@ void client::record(uint64_t end_time, message_header *header) } rtt = end_time - r->start_time; r->active = false; - + int kcycles = rtt>>10; tt("Received response, cid 0x%08x, id %u, length %d, " "rtt %d kcycles", @@ -1694,7 +1694,7 @@ void client::record(uint64_t end_time, message_header *header) time_trace::freeze(); kfreeze(); } - + server_id = first_id[header->cid.server]; if (server_id == -1) { log(NORMAL, "WARNING: response received from unknown " @@ -1712,7 +1712,7 @@ void client::record(uint64_t end_time, message_header *header) /** * class homa_client - Holds information about a single Homa client, * which consists of one thread issuing requests and one or more threads - * receiving responses. + * receiving responses. */ class homa_client : public client { public: @@ -1724,34 +1724,34 @@ class homa_client : public client { void sender(void); virtual void stop_sender(void); bool wait_response(uint64_t id, char* buffer); - + /** @fd: file descriptor for Homa socket. */ int fd; - + /** @stop_sending: true means the sending thread should exit ASAP. */ bool exit_sender; - + /** @stop: true means receiving threads should exit ASAP. */ bool exit_receivers; - + /** @server_exited: just what you'd guess from the name. */ bool sender_exited; - + /** * @sender_buffer: used by the sender to send requests, and also * by measure_unloaded; malloced, size HOMA_MAX_MESSAGE_LENGTH. */ char *sender_buffer; - + /** * @receiver_buffers: one for each receiver thread, used to * receive responses; malloced, size HOMA_MAX_MESSAGE_LENGTH. */ std::vector receiver_buffers; - + /** @receiver: threads that receive responses. */ std::vector receiving_threads; - + /** * @sender: thread that sends requests (may also receive * responses if port_receivers is 0). @@ -1780,7 +1780,7 @@ homa_client::homa_client(int id) log(NORMAL, "Couldn't open Homa socket: %s\n", strerror(errno)); exit(1); } - + if (unloaded) { measure_unloaded(unloaded); sender_exited = true; @@ -1860,7 +1860,7 @@ bool homa_client::wait_response(uint64_t rpc_id, char* buffer) message_header *header = reinterpret_cast(buffer); struct sockaddr_in server_addr; size_t addr_length; - + rpc_id = 0; int length; do { @@ -1910,17 +1910,17 @@ void homa_client::sender() message_header *header = reinterpret_cast(sender_buffer); uint64_t next_start = rdtsc(); char thread_name[50]; - + snprintf(thread_name, sizeof(thread_name), "C%d", id); time_trace::thread_buffer thread_buffer(thread_name); - + while (1) { uint64_t now; uint64_t rpc_id; int server; int status; int slot = get_rinfo(); - + /* Wait until (a) we have reached the next start time * and (b) there aren't too many requests outstanding. */ @@ -1936,13 +1936,13 @@ void homa_client::sender() if ((total_requests - total_responses) < client_port_max) break; } - + rinfos[slot].start_time = now; server = request_servers[next_server]; next_server++; if (next_server >= request_servers.size()) next_server = 0; - + header->length = request_lengths[next_length]; if (header->length > HOMA_MAX_MESSAGE_LENGTH) header->length = HOMA_MAX_MESSAGE_LENGTH; @@ -1985,7 +1985,7 @@ void homa_client::sender() next_interval++; if (next_interval >= request_intervals.size()) next_interval = 0; - + if (receivers_running == 0) { /* There isn't a separate receiver thread; wait for * the response here. */ @@ -2000,11 +2000,11 @@ void homa_client::sender() * @receiver_id: Unique id for this receiver within its client. */ void homa_client::receiver(int receiver_id) -{ +{ char thread_name[50]; snprintf(thread_name, sizeof(thread_name), "R%d.%d", id, receiver_id); time_trace::thread_buffer thread_buffer(thread_name); - + receivers_running++; while (wait_response(0, receiver_buffers[receiver_id])) {} } @@ -2017,7 +2017,7 @@ void homa_client::receiver(int receiver_id) * @buffer: Block of memory to use for request and response; must * contain HOMA_MAX_MESSAGE_LENGTH bytes. * - * Return: Round-trip time to service the request, in rdtsc cycles. + * Return: Round-trip time to service the request, in rdtsc cycles. */ uint64_t homa_client::measure_rtt(int server, int length, char *buffer) { @@ -2077,13 +2077,13 @@ void homa_client::measure_unloaded(int count) int slot; uint64_t ms100 = get_cycles_per_sec()/10; uint64_t end; - + /* Make one request for each size in the distribution, just to warm * up the system. */ for (dist_point &point: dist) measure_rtt(server, point.length, sender_buffer); - + /* Now do the real measurements. Stop with each size after 10 * measurements if more than 0.1 second has elapsed (otherwise * this takes too long). @@ -2110,7 +2110,7 @@ void homa_client::measure_unloaded(int count) /** * class tcp_client - Holds information about a single TCP client, * which consists of one thread issuing requests and one thread receiving - * responses. + * responses. */ class tcp_client : public client { public: @@ -2119,41 +2119,41 @@ class tcp_client : public client { void read(tcp_connection *connection, int pid); void receiver(int id); void sender(void); - - /** + + /** * @connections: One entry for each server in server_addrs; used to * communicate with that server. */ std::vector connections; - + /** * @blocked: Contains all of the connections for which there is * pending output that couldn't be sent because the connection * was backed up. */ std::vector blocked; - + /** @requests: total number of message bytes sent to each server. */ std::vector bytes_sent; - + /** * @requests: total number of message bytes received from each server. */ std::atomic *bytes_rcvd; - + /** * @backups: total number of times that a stream was congested * (many bytes queued for a server, but no response received yet) * when a new message was added to the stream. */ uint64_t backups; - + /** * @epoll_fd: File descriptor used by @receiving_thread to * wait for epoll events. */ int epoll_fd; - + /** * @epollet: EPOLLET if this flag should be used, or 0 otherwise. * We only use edge triggering if there are multiple receiving @@ -2161,13 +2161,13 @@ class tcp_client : public client { * it's faster not to use it). */ int epollet; - + /** @stop: True means background threads should exit. */ bool stop; - + /** @receiver: threads that receive responses. */ std::vector receiving_threads; - + /** * @sender: thread that sends requests (may also receive * responses if port_receivers is 0). @@ -2204,7 +2204,7 @@ tcp_client::tcp_client(int id) "instance: %s\n", strerror(errno)); exit(1); } - + for (uint32_t i = 0; i < server_addrs.size(); i++) { int fd = socket(PF_INET, SOCK_STREAM, 0); if (fd == -1) { @@ -2244,7 +2244,7 @@ tcp_client::tcp_client(int id) connections[connections.size()-1]->set_epoll_events(epoll_fd, EPOLLIN|epollet); } - + for (int i = 0; i < port_receivers; i++) { receiving_threads.emplace_back(&tcp_client::receiver, this, i); } @@ -2264,9 +2264,9 @@ tcp_client::tcp_client(int id) tcp_client::~tcp_client() { int fds[2]; - + stop = true; - + /* In order to wake up the background thread, open a file that is * readable and add it to the epoll set. */ @@ -2284,12 +2284,12 @@ tcp_client::~tcp_client() "pipe: %s\n", strerror(errno)); exit(1); } - + if (sending_thread) sending_thread->join(); for (std::thread& thread: receiving_threads) thread.join(); - + close(fds[0]); close(fds[1]); close(epoll_fd); @@ -2308,22 +2308,22 @@ void tcp_client::sender() { char thread_name[50]; int pid = syscall(__NR_gettid); - + snprintf(thread_name, sizeof(thread_name), "C%d", id); time_trace::thread_buffer thread_buffer(thread_name); - + uint64_t next_start = rdtsc(); message_header header; size_t max_pending = 1; - + /* Index of the next connection in blocked on which to try sending. */ size_t next_blocked = 0; - + while (1) { uint64_t now; int server; int slot = get_rinfo(); - + /* Wait until (a) we have reached the next start time * and (b) there aren't too many requests outstanding. */ @@ -2337,7 +2337,7 @@ void tcp_client::sender() && ((total_requests - total_responses) < client_port_max)) break; - + /* Try to finish I/O on backed up connections. */ if (blocked.size() == 0) continue; @@ -2348,13 +2348,13 @@ void tcp_client::sender() else next_blocked++; } - + rinfos[slot].start_time = now; server = request_servers[next_server]; next_server++; if (next_server >= request_servers.size()) next_server = 0; - + header.length = request_lengths[next_length]; if ((header.length > HOMA_MAX_MESSAGE_LENGTH) && tcp_trunc) header.length = HOMA_MAX_MESSAGE_LENGTH; @@ -2408,12 +2408,12 @@ void tcp_client::sender() void tcp_client::receiver(int receiver_id) { char thread_name[50]; - + snprintf(thread_name, sizeof(thread_name), "R%d.%d", id, receiver_id); time_trace::thread_buffer thread_buffer(thread_name); receivers_running++; int pid = syscall(__NR_gettid); - + /* Each iteration through this loop processes a batch of incoming * responses */ @@ -2421,7 +2421,7 @@ void tcp_client::receiver(int receiver_id) #define MAX_EVENTS 20 struct epoll_event events[MAX_EVENTS]; int num_events; - + tt("calling epoll_wait"); while (1) { num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); @@ -2535,7 +2535,7 @@ void client_stats(uint64_t now) if (clients.size() == 0) return; - + times_per_client = CDF_VALUES/clients.size(); if (times_per_client > NUM_CLIENT_STATS) times_per_client = NUM_CLIENT_STATS; @@ -2625,7 +2625,7 @@ void log_stats() /** * client_cmd() - Parse the arguments for a "client" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int client_cmd(std::vector &words) @@ -2734,14 +2734,14 @@ int client_cmd(std::vector &words) /** * debug_cmd() - Parse the arguments for a "debug" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int debug_cmd(std::vector &words) { int64_t value; size_t num_debug = sizeof(debug)/sizeof(*debug); - + if (words.size() > (num_debug + 1)) { printf("Too many debug values; at most %lu allowed\n", num_debug); @@ -2758,7 +2758,7 @@ int debug_cmd(std::vector &words) * dump_times_cmd() - Parse the arguments for a "dump_times" command and * execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int dump_times_cmd(std::vector &words) @@ -2766,7 +2766,7 @@ int dump_times_cmd(std::vector &words) FILE *f; time_t now; char time_buffer[100]; - + if (words.size() != 2) { printf("Wrong # args; must be 'dump_times file'\n"); return 0; @@ -2777,7 +2777,7 @@ int dump_times_cmd(std::vector &words) strerror(errno)); return 0; } - + time(&now); strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", localtime(&now)); @@ -2813,7 +2813,7 @@ int dump_times_cmd(std::vector &words) /** * info_cmd() - Parse the arguments for an "info" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int info_cmd(std::vector &words) @@ -2821,7 +2821,7 @@ int info_cmd(std::vector &words) const char *workload; char *end; int mtu; - + if (words.size() != 3) { printf("Usage: info workload mtu\n"); return 0; @@ -2844,14 +2844,14 @@ int info_cmd(std::vector &words) /** * log_cmd() - Parse the arguments for a "log" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int log_cmd(std::vector &words) { for (unsigned i = 1; i < words.size(); i++) { const char *option = words[i].c_str(); - + if (strncmp(option, "--", 2) != 0) { string message; for (unsigned j = i; j < words.size(); j++) { @@ -2917,7 +2917,7 @@ int log_cmd(std::vector &words) /** * server_cmd() - Parse the arguments for a "server" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int server_cmd(std::vector &words) @@ -2927,7 +2927,7 @@ int server_cmd(std::vector &words) port_threads = 1; server_ports = 1; server_iovec = false; - + for (unsigned i = 1; i < words.size(); i++) { const char *option = words[i].c_str(); @@ -3009,11 +3009,11 @@ int server_cmd(std::vector &words) /** * stop_cmd() - Parse the arguments for a "stop" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int stop_cmd(std::vector &words) -{ +{ for (unsigned i = 1; i < words.size(); i++) { const char *option = words[i].c_str(); if (strcmp(option, "clients") == 0) { @@ -3044,7 +3044,7 @@ int stop_cmd(std::vector &words) /** * tt_cmd() - Parse the arguments for a "tt" command and execute it. * @words: Command arguments (including the command name as @words[0]). - * + * * Return: Nonzero means success, zero means there was an error. */ int tt_cmd(std::vector &words) @@ -3087,8 +3087,8 @@ int tt_cmd(std::vector &words) * exec_words() - Given a command that has been parsed into words, * execute the command corresponding to the words. * @words: Each entry represents one word of the command, like argc/argv. - * - * Return: Nonzero means success, zero means there was an error. + * + * Return: Nonzero means success, zero means there was an error. */ int exec_words(std::vector &words) { @@ -3130,10 +3130,10 @@ void exec_string(const char *cmd) { const char *p = cmd; std::vector words; - + if (log_file != stdout) log(NORMAL, "Command: %s\n", cmd); - + while (1) { int word_length = strcspn(p, " \t\n"); if (word_length > 0) @@ -3220,20 +3220,20 @@ int main(int argc, char** argv) print_help(argv[0]); exit(0); } - + if (argc > 1) { std::vector words; for (int i = 1; i < argc; i++) words.emplace_back(argv[i]); if (!exec_words(words)) exit(1); - + /* Instead of going interactive, just print stats. * every second. */ log_stats(); } - + // cpu_set_t cores; // CPU_ZERO(&cores); // for (int i = 2; i < 18; i++) @@ -3241,11 +3241,11 @@ int main(int argc, char** argv) // if (sched_setaffinity(0, sizeof(cores), &cores) != 0) // log(NORMAL, "ERROR: couldn't set core affinity: %s\n", // strerror(errno)); - + std::thread logger(log_stats); while (1) { string line; - + printf("%% "); fflush(stdout); if (!std::getline(std::cin, line)) { diff --git a/util/cp_server_ports b/util/cp_server_ports index 3b2ce228..ede0ab35 100755 --- a/util/cp_server_ports +++ b/util/cp_server_ports @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -85,7 +85,7 @@ for workload in workloads: raise Error("No RPC throughput found for experiment %s" % (exp)) tput[workload].append(sum(readings)/len(readings)) - + fig, (ax1, ax2) = plt.subplots(2, figsize=[4, 5]) fig.suptitle("%s Single-Server Throughput" % (options.protocol.capitalize()), y=0.95) diff --git a/util/cp_tcp b/util/cp_tcp index e0e5a304..f6fe40e1 100755 --- a/util/cp_tcp +++ b/util/cp_tcp @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cp_tcp_config b/util/cp_tcp_config index fd300564..fb545d32 100755 --- a/util/cp_tcp_config +++ b/util/cp_tcp_config @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cp_vs_tcp b/util/cp_vs_tcp index 226f26d3..1d963180 100755 --- a/util/cp_vs_tcp +++ b/util/cp_vs_tcp @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/cperf.py b/util/cperf.py index 3c9212a9..6e3ba639 100644 --- a/util/cperf.py +++ b/util/cperf.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2020 Stanford University +# Copyright (c) 2020-2022 Stanford University # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -903,10 +903,10 @@ def get_buckets(rtts, total): def set_unloaded(experiment): """ Compute the optimal RTTs for each message size. - + experiment: Name of experiment that measured RTTs under low load """ - + # Find (or generate) unloaded data for comparison. files = sorted(glob.glob("%s/%s-*.rtts" % (log_dir, experiment))) if len(files) == 0: @@ -958,7 +958,7 @@ def get_digest(experiment): sys.stdout.write("#") sys.stdout.flush() print("") - + if len(unloaded_p50) == 0: raise Exception("No unloaded data: must invoked set_unloaded") @@ -1075,7 +1075,7 @@ def start_slowdown_plot(title, max_y, x_experiment, size=10, top_axis.set_xlabel("Cumulative % of Messages", size=size) top_axis.xaxis.set_label_position('top') - if x_experiment != None: + if x_experiment != None: # Generate x-axis labels ticks = [] labels = [] @@ -1107,7 +1107,7 @@ def cdf_xaxis(ax, x_values, counts, num_ticks, size=10): """ Generate labels for an x-axis that is scaled nonlinearly to reflect a particular distribution of samples. - + ax: matplotlib Axes object for the plot x: List of x-values counts: List giving the number of samples for each point in x @@ -1137,7 +1137,7 @@ def cdf_xaxis(ax, x_values, counts, num_ticks, size=10): target_count = (total*tick)/(num_ticks-1) ax.set_xticks(ticks) ax.set_xticklabels(labels, size=size) - + def make_histogram(x, y, init=None, after=True): """ diff --git a/util/diff_metrics.py b/util/diff_metrics.py index be2475fa..397f2e93 100755 --- a/util/diff_metrics.py +++ b/util/diff_metrics.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2018-2020 Stanford University +# Copyright (c) 2018-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/dist.cc b/util/dist.cc index d312b712..ae704aa0 100644 --- a/util/dist.cc +++ b/util/dist.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,7 +30,7 @@ * @fixed: If a uniform workload has been requested, this variable * will be filled in with the fixed size for that workload; * otherwise the value will be set to 0. - * + * * Return: If @name refers to a valid (non-uniform) workload, the * return value will be appended to the first point in * the array for that workload. Otherwise the return value @@ -40,7 +40,7 @@ dist_point *dist_lookup(const char *dist, int *fixed) { char *end; int length; - + /* First check for a fixed-size distribution. */ length = strtol(dist, &end, 10); if ((length != 0) && (*end == 0)) { @@ -48,7 +48,7 @@ dist_point *dist_lookup(const char *dist, int *fixed) return NULL; } *fixed = 0; - + if (strcmp(dist, "w1") == 0) { return w1; } else if (strcmp(dist, "w2") == 0) { @@ -59,7 +59,7 @@ dist_point *dist_lookup(const char *dist, int *fixed) return w4; } else if (strcmp(dist, "w5") == 0) { return w5; - } + } return NULL; } @@ -70,7 +70,7 @@ dist_point *dist_lookup(const char *dist, int *fixed) * @rand_gen: Random number generator to use in generating samples. * @num_samples: How many samples to generate. * @sizes: The generated samples are appended to this vector. - * + * * Return: Non-zero means success; zero means dist isn't a valid * workload name. */ @@ -78,7 +78,7 @@ void dist_sample(std::vector &points, std::mt19937 *rand_gen, int num_samples, std::vector &sizes) { std::uniform_real_distribution uniform_dist(0.0, 1.0); - + for (int i = 0; i < num_samples; i++) { double cdf_fraction = uniform_dist(*rand_gen); for (dist_point &p: points) { @@ -94,14 +94,14 @@ void dist_sample(std::vector &points, std::mt19937 *rand_gen, * dist_mean() - Returns the mean value in a distribution. * @points: Specifies the distribution to use (previous result * from dist_get). - * + * * Return: the mean value, or a negative value if dist isn't a valid * workload name. */ double dist_mean(std::vector &points) { double mean, prev_fraction; - + mean = 0; prev_fraction = 0.0; for (dist_point &p: points) { @@ -114,7 +114,7 @@ double dist_mean(std::vector &points) /** * dist_get() - Returns a distribution, potentially merging buckets to - * reduce the total number of points. + * reduce the total number of points. * @dist: Name of the desired distribution, using the same syntax * as for dist_sample. * @max_length: Assume that any lengths longer than this value will @@ -141,7 +141,7 @@ std::vector dist_get(const char *dist, int max_length, int length, buck_short; dist_point *points, *prev; double last_buck_fraction; - + points = dist_lookup(dist, &length); if (length != 0) { result.emplace_back(length, 1.0); @@ -188,13 +188,13 @@ std::vector dist_get(const char *dist, int max_length, * packets (such as grants) that are required in the normal case. * @length: Number of bytes in the message payload. * @mtu: Maximum size of an Ethernet payload. - * - * Return: Total overhead bytes for a message of the given length. + * + * Return: Total overhead bytes for a message of the given length. */ int dist_msg_overhead(int length, int mtu) { int packet_data, packets, grants, common; - + /* Sizes of various sources of overhead. */ int preamble = 8; int ether = 18; @@ -204,7 +204,7 @@ int dist_msg_overhead(int length, int mtu) int homa_grant = 33; int unsched = 70000; int grant_increment = 10000; - + packet_data = mtu - (ip + homa_data); packets = (length + packet_data - 1)/packet_data; if (length <= unsched) @@ -228,7 +228,7 @@ int dist_msg_overhead(int length, int mtu) double dist_overhead(std::vector &points, int mtu) { double overhead, prev_fraction; - + overhead = 0.0; prev_fraction = 0.0; for (dist_point &p: points) { @@ -1987,7 +1987,7 @@ dist_point w4[] = { {895802, 0.97136}, {917977, 0.97173}, {940700, 0.9721}, - + /* Alternate form that doesn't flatten out when the maximum message * size is 1000000. */ diff --git a/util/dist.h b/util/dist.h index 0d7d9f2a..16f73645 100644 --- a/util/dist.h +++ b/util/dist.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,13 +30,13 @@ struct dist_point { * sizeof(message_header). */ int length; - + /** * @fraction: fraction of all messages that are this size * or smaller. */ double fraction; - + dist_point(int length, double fraction) : length(length), fraction(fraction) {} diff --git a/util/get_time_trace.c b/util/get_time_trace.c index 8a2b8e21..995b64fe 100644 --- a/util/get_time_trace.c +++ b/util/get_time_trace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -44,10 +44,10 @@ int main(int argc, char** argv) { printf("Not enough space in buffer for complete timetrace.\n"); } buffer[length-1] = 0; - + double cps = get_cycles_per_sec(); printf("Cycles per second: %g\n", cps); - + // Scan through the records in the buffer. For each record, replace // the timestamp with more detailed information in ns, and output // the modified record. @@ -69,7 +69,7 @@ int main(int argc, char** argv) { ns = (1e09 * (double)(stamp - start_time)) / cps; delta_ns = (1e09 * (double)(stamp - prev_time)) / cps; printf("%8.1f ns (+%6.1f ns):", ns, delta_ns); - + for (current = stamp_end; (*current != 0) && (*current != '\n'); current++) { diff --git a/util/homa_prio.cc b/util/homa_prio.cc index 30643fe0..c3575823 100644 --- a/util/homa_prio.cc +++ b/util/homa_prio.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2020 Stanford University +/* Copyright (c) 2020-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,26 +50,26 @@ Msg_Type log_level = NORMAL; extern void log(Msg_Type type, const char *format, ...) __attribute__((format(printf, 2, 3))); -/** +/** * struct interval - Keeps statistics for a range of message sizes * (corresponds to a single line of the homa_metrics file). */ struct interval { /** @max_size: largest message size (in bytes) in this interval. */ int max_size; - + /** * @total_bytes: total number of bytes (over all time) in incoming * messages in this size range. */ int64_t total_bytes; - + /** * @total_messages: an estimate of the total number of messages * in this interval (exact statistics are not kept). */ int64_t total_messages; - + /** * @unsched_bytes: estimate of the total unscheduled bytes in * incoming messages in this range (it's an estimate because we @@ -77,7 +77,7 @@ struct interval { * that). */ int64_t unsched_bytes; - + interval(int max_size, int64_t total_bytes, int64_t total_messages) : max_size(max_size) , total_bytes(total_bytes) @@ -93,14 +93,14 @@ struct metrics { * increasing order of message length. */ std::vector intervals; - + /* Homa metrics with the same name. */ int64_t large_msg_count; int64_t large_msg_bytes; - + /** @total_bytes: total bytes received across all message sizes. */ int64_t total_bytes; - + /** * @estimated_msgs: total number of messages received (only an * estimate; exact counts aren't kept). @@ -167,7 +167,7 @@ void print_help(const char *name) * get_param() - Read a Homa sysctl value. * @name: Name of the desired parameter. * @value: The value of the parameters stored here. - * + * * Return: True for success, false means the file couldn't be read or * didn't contain an integer value (errors are logged after failures) */ @@ -189,7 +189,7 @@ bool get_param(const char *name, int *value) return false; } f.close(); - + char *end; *value = strtol(line.c_str(), &end, 10); if (end == line.c_str()) { @@ -233,7 +233,7 @@ void read_metrics(const char *path, metrics *metrics) const char *s; std::string value; char *end; - + size_t index = line.find(" "); if (index == std::string::npos) goto bad_line; @@ -243,7 +243,7 @@ void read_metrics(const char *path, metrics *metrics) && (strcmp(s, "large_msg_bytes") != 0) && (strcmp(s, "large_msg_count") != 0)) continue; - + // Extract the count. index = line.find_first_not_of(" ", index+1); if (index == std::string::npos) @@ -255,7 +255,7 @@ void read_metrics(const char *path, metrics *metrics) value.c_str(), line.c_str()); continue; } - + // Record data about the line. if (symbol[0] == 'm') { s += 10; @@ -266,7 +266,7 @@ void read_metrics(const char *path, metrics *metrics) "number\n", symbol.c_str()); continue; } - + /* See whether (a) there is an existing entry to * increment, or (b) we need to add a new entry. */ @@ -312,7 +312,7 @@ void read_metrics(const char *path, metrics *metrics) metrics->total_bytes += count; } continue; - + bad_line: log(NORMAL, "Couldn't parse line of metrics file: '%s'\n", line.c_str()); @@ -337,7 +337,7 @@ void compute_cutoffs(metrics *diff, int cutoffs[8], int num_priorities, { int64_t total_bytes, total_unsched_bytes; int prev_size; - + // Compute the unscheduled bytes received over the interval. total_bytes = 0; total_unsched_bytes = 0; @@ -361,7 +361,7 @@ void compute_cutoffs(metrics *diff, int cutoffs[8], int num_priorities, } total_bytes += diff->large_msg_bytes; total_unsched_bytes += diff->large_msg_count * rtt_bytes; - + // Divide priorities between scheduled and unscheduled packets. int64_t unsched_prios = unsched; if (unsched == 0) { @@ -383,7 +383,7 @@ void compute_cutoffs(metrics *diff, int cutoffs[8], int num_priorities, "%.1f MB unsched (%.1f%%), %ld unsched priorities\n", total_messages, total_mb, unsched_mb, 100.0*unsched_mb/total_mb, unsched_prios); - + // Compute cutoffs for unscheduled priorities. int64_t bytes_per_prio; if (unsched_prios < num_priorities) @@ -409,7 +409,7 @@ void compute_cutoffs(metrics *diff, int cutoffs[8], int num_priorities, if (next_cutoff_bytes >= total_unsched_bytes) break; } - + } for ( ; next_cutoff >= 0; next_cutoff--) cutoffs[next_cutoff] = HOMA_MAX_MESSAGE_LENGTH; @@ -448,10 +448,10 @@ void install_cutoffs(int cutoffs[8]) * @prev: Cumulative metrics gathered earlier * @cur: Cumulative metrics gathered more recently * @diff: Will be modified to hold all the changes between @prev and @cur - * + * * Return: True means the difference was computed successfully; false means * the metrics didn't have the same structure, so a difference - * it doesn't make sense. + * it doesn't make sense. */ bool diff_metrics(metrics *prev, metrics *cur, metrics *diff) { @@ -554,7 +554,7 @@ bool parse_double(const char **argv, int i, double *value) { double num; char *end; - + if (argv[i+1] == NULL) { printf("No value provided for %s\n", argv[i]); return false; @@ -583,7 +583,7 @@ bool parse_int(const char **argv, int i, int *value) { int num; char *end; - + if (argv[i+1] == NULL) { printf("No value provided for %s\n", argv[i]); return false; @@ -599,7 +599,7 @@ bool parse_int(const char **argv, int i, int *value) } int main(int argc, const char** argv) -{ +{ /* Parse arguments. */ for (int i = 1; i < argc; i++) { const char *option = argv[i]; @@ -648,7 +648,7 @@ int main(int argc, const char** argv) exit(1); } } - + metrics m[2]; metrics *prev_metrics = &m[0]; metrics *cur_metrics = &m[1]; @@ -677,7 +677,7 @@ int main(int argc, const char** argv) log(NORMAL, "get_param failed for rtt_bytes\n"); continue; } - + // Don't update the cutoffs until we've collected enough // data to provide reasonable statistics. if ((diff.total_messages < min_messages) || @@ -686,7 +686,7 @@ int main(int argc, const char** argv) metrics *tmp = prev_metrics; prev_metrics = cur_metrics; cur_metrics = tmp; - + if (num_priorities != prev_num_priorities) { log(NORMAL, "\n"); log(NORMAL, "num_priorities changed from %d to %d\n", @@ -699,7 +699,7 @@ int main(int argc, const char** argv) prev_num_priorities = num_priorities; continue; } - + int deciles[9]; get_deciles(&diff, deciles); log(NORMAL, "\n"); diff --git a/util/homa_test.cc b/util/homa_test.cc index b9687e51..5a091ddf 100644 --- a/util/homa_test.cc +++ b/util/homa_test.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -76,7 +76,7 @@ void send_fd(int fd, struct sockaddr *addr, char *request) { uint64_t id; int status; - + sleep(1); status = homa_send(fd, request, length, addr, sizeof(*addr), &id); if (status < 0) { @@ -292,16 +292,16 @@ void test_poll(int fd, char *request) addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(500); - + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { printf("Couldn't bind socket to Homa port %d: %s\n", ntohl(addr.sin_port), strerror(errno)); return; } - + std::thread thread(send_fd, fd, (struct sockaddr *) &addr, request); thread.detach(); - + result = poll(&poll_info, 1, -1); if (result > 0) { printf("Poll succeeded with mask 0x%x\n", poll_info.revents); @@ -309,7 +309,7 @@ void test_poll(int fd, char *request) printf("Poll failed: %s\n", strerror(errno)); return; } - + source_length = sizeof(source); result = homa_recv(fd, message, sizeof(message), HOMA_RECV_REQUEST, (struct sockaddr *) &source, &source_length, &id, @@ -440,7 +440,7 @@ void test_shutdown(int fd) printf("Error in homa_recv: %s\n", strerror(errno)); } - + /* Make sure that future reads also fail. */ addr_length = sizeof(addr); result = homa_recv(fd, message, sizeof(message), HOMA_RECV_RESPONSE, @@ -472,7 +472,7 @@ void test_stream(int fd, struct sockaddr *dest) int64_t bytes_sent = 0; int64_t start_bytes = 0; double rate; - + if (count > MAX_RPCS) { printf("Count too large; reducing from %d to %d\n", count, MAX_RPCS); @@ -492,7 +492,7 @@ void test_stream(int fd, struct sockaddr *dest) return; } } - + /* Each iteration through the following the loop waits for a * response to an outstanding request, then initiates a new * request. @@ -521,7 +521,7 @@ void test_stream(int fd, struct sockaddr *dest) bytes_sent += length; if (bytes_sent > 1001000000) break; - + /* Don't start timing until we've sent a few bytes to warm * everything up. */ @@ -535,7 +535,7 @@ void test_stream(int fd, struct sockaddr *dest) end_cycles - start_cycles); printf("Homa throughput using %d concurrent %d byte messages: " "%.2f GB/sec\n", count, length, rate*1e-09); - + for (i = 0; i < count; i++) free(buffers[i]); } @@ -597,7 +597,7 @@ void test_tcp(char *server_name, int port) struct sockaddr *dest; int status, i; int buffer[250000]; - + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; @@ -609,7 +609,7 @@ void test_tcp(char *server_name, int port) } dest = matching_addresses->ai_addr; ((struct sockaddr_in *) dest)->sin_port = htons(port); - + int stream = socket(PF_INET, SOCK_STREAM, 0); if (stream == -1) { printf("Couldn't open client socket: %s\n", strerror(errno)); @@ -622,21 +622,21 @@ void test_tcp(char *server_name, int port) } int flag = 1; setsockopt(stream, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); - + /* Warm up. */ buffer[0] = length; buffer[1] = length; seed_buffer(&buffer[2], sizeof32(buffer) - 2*sizeof32(int), seed); for (i = 0; i < 10; i++) tcp_ping(stream, buffer, length); - + uint64_t times[count+1]; for (i = 0; i < count; i++) { times[i] = rdtsc(); tcp_ping(stream, buffer, length); } times[count] = rdtsc(); - + for (i = 0; i < count; i++) { times[i] = times[i+1] - times[i]; } @@ -663,7 +663,7 @@ void test_tcpstream(char *server_name, int port) int64_t start_bytes = 0; uint64_t start_cycles = 0; double elapsed, rate; - + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; @@ -675,7 +675,7 @@ void test_tcpstream(char *server_name, int port) } dest = matching_addresses->ai_addr; ((struct sockaddr_in *) dest)->sin_port = htons(port); - + int fd = socket(PF_INET, SOCK_STREAM, 0); if (fd == -1) { printf("Couldn't open client socket: %s\n", strerror(errno)); @@ -689,7 +689,7 @@ void test_tcpstream(char *server_name, int port) int flag = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); buffer[0] = -1; - + while (1) { if (write(fd, buffer, length) != length) { printf("Socket write failed: %s\n", strerror(errno)); @@ -698,7 +698,7 @@ void test_tcpstream(char *server_name, int port) bytes_sent += length; if (bytes_sent > 1010000000) break; - + /* Don't start timing until we've sent a few bytes to warm * everything up. */ @@ -706,7 +706,7 @@ void test_tcpstream(char *server_name, int port) start_bytes = bytes_sent; start_cycles = rdtsc(); } - + } elapsed = to_seconds(rdtsc() - start_cycles); rate = ((double) bytes_sent - start_bytes) / elapsed; @@ -760,12 +760,12 @@ int main(int argc, char** argv) struct addrinfo hints; char *host, *port_name; char buffer[HOMA_MAX_MESSAGE_LENGTH]; - + if ((argc >= 2) && (strcmp(argv[1], "--help") == 0)) { print_help(argv[0]); exit(0); } - + if (argc < 3) { printf("Usage: %s host:port [options] op op ...\n", argv[0]); exit(1); @@ -823,7 +823,7 @@ int main(int argc, char** argv) exit(1); } } - + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; @@ -838,12 +838,12 @@ int main(int argc, char** argv) int *ibuf = reinterpret_cast(buffer); ibuf[0] = ibuf[1] = length; seed_buffer(&ibuf[2], sizeof32(buffer) - 2*sizeof32(int), seed); - + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_HOMA); if (fd < 0) { printf("Couldn't open Homa socket: %s\n", strerror(errno)); } - + for ( ; nextArg < argc; nextArg++) { if (strcmp(argv[nextArg], "close") == 0) { test_close(); diff --git a/util/metrics.py b/util/metrics.py index a877d0b9..e7ef0325 100755 --- a/util/metrics.py +++ b/util/metrics.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -332,7 +332,7 @@ def scale_number(number): else: us_per = (time/calls)/(cpu_khz/1e03) print("App/syscall %6.2f %7.2f us/syscall" % (cores, us_per)) - + print("\nLock Misses:") print("------------") print(" Misses/sec. ns/Miss %CPU") @@ -346,7 +346,7 @@ def scale_number(number): print("%-10s %s %6.1f %5.1f" % (lock, scale_number(misses/elapsed_secs), cycles_per_miss/(cpu_khz/1e06), 100.0*cycles/time_delta)) - + total_messages = float(deltas["requests_received"] + deltas["responses_received"]) if total_messages > 0.0: @@ -358,7 +358,7 @@ def scale_number(number): - sleep_percent)) print("Arrival while polling: %4.1f%%" % (poll_percent)) print("Arrival while sleeping: %4.1f%%" % (sleep_percent)) - + print("\nMiscellaneous:") print("--------------") if packets_received > 0: @@ -379,7 +379,7 @@ def scale_number(number): throttled_secs = float(deltas["throttled_cycles"])/(cpu_khz * 1000.0) print("Pacer throughput: %5.2f Gbps" % ( deltas["pacer_bytes"]*8e-09/throttled_secs)) - + print("\nCanaries (possible problem indicators):") print("---------------------------------------") for symbol in ["requests_queued", "responses_queued"]: @@ -422,4 +422,3 @@ def scale_number(number): % ("acks_per_rpc", 1000.0 * deltas["packets_sent_ACK"] / deltas["responses_received"])) - \ No newline at end of file diff --git a/util/receive_raw.c b/util/receive_raw.c index 9c70aba3..0e79978f 100644 --- a/util/receive_raw.c +++ b/util/receive_raw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -39,7 +39,7 @@ int main(int argc, char** argv) { char buffer[BUF_SIZE]; struct ip* ip_header = (struct ip *) buffer; int header_length; - + if (argc >= 2) { protocol = strtol(argv[1], NULL, 10); if (protocol == 0) { @@ -50,13 +50,13 @@ int main(int argc, char** argv) { } else { protocol = IPPROTO_HOMA; } - + fd = socket(AF_INET, SOCK_RAW, protocol); if (fd < 0) { printf("Couldn't open raw socket: %s\n", strerror(errno)); exit(1); } - + while (1) { size = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, 0); if (size < 0) { diff --git a/util/send_raw.c b/util/send_raw.c index 606ab36f..1f4a1d41 100644 --- a/util/send_raw.c +++ b/util/send_raw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -39,7 +39,7 @@ int main(int argc, char** argv) { int protocol; struct sockaddr_in *addr; uint8_t *bytes; - + if (argc < 3) { printf("Usage: %s hostName contents [protocol]\n", argv[0]); exit(1); @@ -56,7 +56,7 @@ int main(int argc, char** argv) { } else { protocol = IPPROTO_HOMA; } - + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; @@ -70,13 +70,13 @@ int main(int argc, char** argv) { bytes = (uint8_t *) &addr->sin_addr; printf("Destination address: %x (%d.%d.%d.%d)\n", addr->sin_addr.s_addr, bytes[0], bytes[1], bytes[2], bytes[3]); - + fd = socket(AF_INET, SOCK_RAW, protocol); if (fd < 0) { printf("Couldn't open raw socket: %s\n", strerror(errno)); exit(1); } - + status = sendto(fd, message, strlen(message), 0, result->ai_addr, result->ai_addrlen); if (status < 0) { diff --git a/util/server.cc b/util/server.cc index d50fdac5..6fdee848 100644 --- a/util/server.cc +++ b/util/server.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,7 +20,7 @@ * * Usage: * server [options] - * + * * Type "server --help" for documenation on the options. */ @@ -66,13 +66,13 @@ void homa_server(int port) struct sockaddr_in source; size_t source_length; int length; - + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_HOMA); if (fd < 0) { printf("Couldn't open Homa socket: %s\n", strerror(errno)); return; } - + memset(&addr_in, 0, sizeof(addr_in)); addr_in.sin_family = AF_INET; addr_in.sin_port = htons(port); @@ -87,7 +87,7 @@ void homa_server(int port) uint64_t id = 0; int seed; int result; - + source_length = sizeof(source); length = homa_recv(fd, message, sizeof(message), HOMA_RECV_REQUEST, (struct sockaddr *) &source, @@ -150,7 +150,7 @@ void tcp_connection(int fd, struct sockaddr_in source) char buffer[1000000]; int cur_length = 0; bool streaming = false; - + int *int_buffer = reinterpret_cast(buffer); if (verbose) printf("New TCP socket from %s\n", print_address(&source)); @@ -166,7 +166,7 @@ void tcp_connection(int fd, struct sockaddr_in source) } if (result == 0) break; - + /* The connection can be used in two modes. If the first * word received is -1, then the connection is in streaming * mode: we just read bytes and throw them away. If the @@ -267,12 +267,12 @@ void tcp_server(int port) int main(int argc, char** argv) { int next_arg; int num_ports = 1; - + if ((argc >= 2) && (strcmp(argv[1], "--help") == 0)) { print_help(argv[0]); exit(0); } - + for (next_arg = 1; next_arg < argc; next_arg++) { if (strcmp(argv[next_arg], "--help") == 0) { print_help(argv[0]); @@ -305,11 +305,11 @@ int main(int argc, char** argv) { exit(1); } } - + for (int i = 0; i < num_ports; i++) { std::thread thread(homa_server, port+i); thread.detach(); } - + tcp_server(port); } diff --git a/util/service.py b/util/service.py index bac32e99..ce8537ae 100755 --- a/util/service.py +++ b/util/service.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/test_time_trace.c b/util/test_time_trace.c index 4938cc23..2c4d6a83 100644 --- a/util/test_time_trace.c +++ b/util/test_time_trace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/util/test_utils.cc b/util/test_utils.cc index 01257319..cadba771 100644 --- a/util/test_utils.cc +++ b/util/test_utils.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,7 +35,7 @@ * is printed. * @buffer: Buffer to check * @length: Number of bytes in buffer - * + * * Return: the seed value that was used to generate the buffer. */ int check_buffer(void *buffer, size_t length) @@ -44,7 +44,7 @@ int check_buffer(void *buffer, size_t length) int num_ints = (length + sizeof(int) - 1)/sizeof(int); int seed = int_buffer[0]; int i; - + for (i = 0; i < num_ints; i++) { if (int_buffer[i] != seed + i) { printf("Bad value at index %d in " @@ -59,7 +59,7 @@ int check_buffer(void *buffer, size_t length) /** * get_cycles_per_sec(): calibrate the RDTSC timer. - * + * * Return: the number of RDTSC clock ticks per second. */ double get_cycles_per_sec() @@ -68,7 +68,7 @@ double get_cycles_per_sec() if (cps != 0) { return cps; } - + // Take parallel time readings using both rdtsc and gettimeofday. // After 10ms have elapsed, take the ratio between these readings. @@ -164,7 +164,7 @@ void seed_buffer(void *buffer, size_t length, int seed) int *int_buffer = (int *) buffer; int num_ints = (length + sizeof(int) - 1)/sizeof(int); int i; - + for (i = 0; i < num_ints; i++) { int_buffer[i] = seed + i; } @@ -175,9 +175,9 @@ void seed_buffer(void *buffer, size_t length, int seed) * @addr: The address to print * @buffer: Where to store the human readable description. * @size: Number of bytes available in buffer. - * + * * Return: The address of the human-readable string (buffer). - * + * * This function keeps a collection of static buffers to hold the printable * strings, so callers don't have to worry about allocating space, even if * several addresses are in use at once. This function is also thread-safe. @@ -188,7 +188,7 @@ const char *print_address(struct sockaddr_in *addr) #define NUM_BUFFERS 16 static char buffers[NUM_BUFFERS][BUF_SIZE]; static std::atomic next_buffer = 0; - + char *buffer = buffers[next_buffer.fetch_add(1) & (NUM_BUFFERS-1)]; if (addr->sin_family != AF_INET) { @@ -209,7 +209,7 @@ const char *print_address(struct sockaddr_in *addr) * to_seconds() - Given an elapsed time measured in cycles, return a * floating-point number giving the corresponding time in seconds. * @cycles: Difference between the results of two calls to rdtsc. - * + * * Return: The time in seconds corresponding to cycles. */ double to_seconds(uint64_t cycles) diff --git a/util/test_utils.h b/util/test_utils.h index 1c7dcb48..99f0d103 100644 --- a/util/test_utils.h +++ b/util/test_utils.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,7 +22,7 @@ extern "C" { #endif - + #define sizeof32(type) static_cast(sizeof(type)) extern int check_buffer(void *buffer, size_t length); diff --git a/util/time_trace.cc b/util/time_trace.cc index 82b5aa46..dc7beb22 100644 --- a/util/time_trace.cc +++ b/util/time_trace.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2020 Stanford University +/* Copyright (c) 2014-2022 Stanford University * * Permission to use, copy, modify, and distribute this software for any purpose * with or without fee is hereby granted, provided that the above copyright @@ -75,9 +75,9 @@ void time_trace::print_internal(std::string *s, FILE *f) { std::vector buffers; - + freeze(); - + /* Make a copy of thread_buffers in order to avoid potential * synchronization issues with new threads modifying it. */ @@ -130,7 +130,7 @@ time_trace::print_internal(std::string *s, FILE *f) current[i] = (current[i] + 1) % buffer::BUFFER_SIZE; } } - + // Output an initial (synthetic) record with the starting time. if (s != NULL) { char message[1000]; diff --git a/util/time_trace.h b/util/time_trace.h index 0feebef5..7f2c3f4f 100644 --- a/util/time_trace.h +++ b/util/time_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020 Stanford University +/* Copyright (c) 2020-2022 Stanford University * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -54,7 +54,7 @@ class time_trace { /** @frozen: nonzero means that the timetrace is already frozen. */ static int frozen; - + protected: class buffer; @@ -69,7 +69,7 @@ class time_trace { * buffers. Entries get deleted only by free_unused. */ static std::vector thread_buffers; - + public: /** @@ -117,7 +117,7 @@ class time_trace { uint32_t arg2; uint32_t arg3; }; - + /** * class buffer - Represents a sequence of events generated by a single * thread. Has a fixed capacity, so slots are re-used on a circular @@ -135,7 +135,7 @@ class time_trace { public: /** @name: name that identifies this buffer/thread. */ std::string name; - + /** * @BUFFER_SIZE_EXP: determines the number of events we can * retain, as an exponent of 2. @@ -158,14 +158,14 @@ class time_trace { * call to record. */ int next_index; - - /** + + /** * @ref_count: number of thread_buffer objects that reference * this buffer. When this count becomes 0, the buffer can be * deleted in the next call to time_trace::cleanup. */ int ref_count; - + /** * @events: Holds information from the most recent calls to record. */ @@ -173,7 +173,7 @@ class time_trace { friend class time_trace; }; - + public: /** * class thread_buffer - One of these should be instantiated as a @@ -185,7 +185,7 @@ class time_trace { public: thread_buffer(std::string name); ~thread_buffer(); - + protected: /* The buffer associated with this thread. Malloc-ed. The * "official" reference to this is the one in thread_buffers. diff --git a/util/ttcore.py b/util/ttcore.py index f27646f9..b42e4a83 100755 --- a/util/ttcore.py +++ b/util/ttcore.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/ttgrep.py b/util/ttgrep.py index 30aab29f..5aab4fcb 100755 --- a/util/ttgrep.py +++ b/util/ttgrep.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/ttmerge.py b/util/ttmerge.py index e765ce14..f52b7242 100755 --- a/util/ttmerge.py +++ b/util/ttmerge.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -37,7 +37,7 @@ # first: Timestamp of first entry # offset: How much to add to times in this file so they align # with times in the other files -# time: Time of the current line, adjusted by offset +# time: Time of the current line, adjusted by offset # suffix: Everything on the current line after the times files = [] diff --git a/util/ttoffset.py b/util/ttoffset.py index 3e86daf0..69627bd2 100755 --- a/util/ttoffset.py +++ b/util/ttoffset.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/ttprint.py b/util/ttprint.py index 12d95ad3..512d1ddd 100755 --- a/util/ttprint.py +++ b/util/ttprint.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/ttrange.py b/util/ttrange.py index 3659d97f..9cae919e 100755 --- a/util/ttrange.py +++ b/util/ttrange.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/ttsum.py b/util/ttsum.py index 27f92797..387d01a7 100755 --- a/util/ttsum.py +++ b/util/ttsum.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright (c) 2019-2020 Stanford University +# Copyright (c) 2019-2022 Stanford University # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/util/use_memory.c b/util/use_memory.c index 6c2d79bc..12d26c67 100644 --- a/util/use_memory.c +++ b/util/use_memory.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, Stanford University +/* Copyright (c) 2019-2022 Stanford University * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,7 +27,7 @@ int main(int argc, char** argv) { int gbytes, i, j; - + if (argc != 2) { printf("Usage: %s gbytes\n", argv[0]); exit(1); @@ -38,7 +38,7 @@ int main(int argc, char** argv) { argv[1]); exit(1); } - + // Each iteration through the following loop allocates 10^9 bytes // of memory and fills it with random values. for (i = 0; i < gbytes; i++) {