Skip to content

Commit c80dd47

Browse files
committed
Initialized RSS to distribute packets evenly to multiple cores, added perf and statistic counters to IxgbeDriver, hijacked Ping messages to act as triggers to set up state
1 parent 8a5d249 commit c80dd47

File tree

5 files changed

+145
-12
lines changed

5 files changed

+145
-12
lines changed

src/native/Ixgbe.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */
3535
#define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */
3636

37+
#define IXGBE_EITR_CNT_WDIS 0x80000000
38+
3739
enum l4_type { l4_type_udp = 0, l4_type_tcp, l4_type_sctp, l4_type_rsv };
3840

3941
#define ETHHDR_LEN 14

src/native/IxgbeDriver.cc

Lines changed: 114 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ void ebbrt::IxgbeDriver::Create(pci::Device& dev) {
2828
ixgbe_dev->ebb_ =
2929
IxgbeDriverRep::Create(ixgbe_dev, ebb_allocator->AllocateLocal());
3030

31+
// only even core numbers
32+
if(static_cast<int>(Cpu::Count()) > 1) {
33+
kassert(static_cast<int>(Cpu::Count()) % 2 == 0);
34+
}
35+
3136
// initialize per core rx and tx queues
3237
for (size_t i = 0; i < Cpu::Count(); i++) {
3338
ixgbe_dev->SetupMultiQueue(i);
@@ -44,7 +49,47 @@ const ebbrt::EthernetAddress& ebbrt::IxgbeDriver::GetMacAddress() {
4449
return mac_addr_;
4550
}
4651

52+
void ebbrt::IxgbeDriver::DumpStats() {
53+
for (size_t i = 0; i < Cpu::Count(); i++) {
54+
ebbrt::kprintf("Core %d STATS:\n", (int)i);
55+
ebbrt::kprintf("\t num_recv_itrs:%lld\n", ixgmq[i]->stat_num_itr);
56+
ebbrt::kprintf("\t num_send:%lld\n", ixgmq[i]->stat_num_send);
57+
ebbrt::kprintf("\t num_rx_desc_proc:%lld\n", ixgmq[i]->stat_num_rx);
58+
ebbrt::kprintf("\t num_tx_desc_proc:%lld\n", ixgmq[i]->stat_num_tx);
59+
60+
// reset to 0
61+
ixgmq[i]->stat_num_itr = 0;
62+
ixgmq[i]->stat_num_send = 0;
63+
ixgmq[i]->stat_num_rx = 0;
64+
ixgmq[i]->stat_num_tx = 0;
65+
66+
if(ixgmq[i]->stat_perf == false) {
67+
ixgmq[i]->perfCycles = ebbrt::perf::PerfCounter(ebbrt::perf::PerfEvent::cycles);
68+
ixgmq[i]->perfCycles.Start();
69+
ixgmq[i]->perfInst = ebbrt::perf::PerfCounter(ebbrt::perf::PerfEvent::instructions);
70+
ixgmq[i]->perfInst.Start();
71+
ixgmq[i]->stat_perf =true;
72+
} else {
73+
ixgmq[i]->perfCycles.Stop();
74+
ixgmq[i]->perfInst.Stop();
75+
double cyc = static_cast<double>(ixgmq[i]->perfCycles.Read());
76+
double inst = static_cast<double>(ixgmq[i]->perfInst.Read());
77+
78+
ebbrt::kprintf("Core %d PMC:\n", (int)i);
79+
ebbrt::kprintf("\t cycles:%llf \n", cyc);
80+
ebbrt::kprintf("\t instructions:%llf\n", inst);
81+
ebbrt::kprintf("\t ipc: %llf\n", inst/cyc);
82+
ixgmq[i]->stat_perf = false;
83+
}
84+
}
85+
}
86+
4787
void ebbrt::IxgbeDriver::Send(std::unique_ptr<IOBuf> buf, PacketInfo pinfo) {
88+
#ifdef STATS_EN
89+
if(pinfo.get_stats) {
90+
DumpStats();
91+
}
92+
#endif
4893
ebb_->Send(std::move(buf), std::move(pinfo));
4994
}
5095

@@ -175,14 +220,21 @@ void ebbrt::IxgbeDriverRep::AddTx(uint64_t pa, uint64_t len,
175220

176221
ixgmq_.tx_last_tail_ = ixgmq_.tx_tail_;
177222
ixgmq_.tx_tail_ = (tail + 1) % ixgmq_.tx_size_;
223+
#ifdef STATS_EN
224+
ixgmq_.stat_num_tx ++;
225+
#endif
178226
}
179227

180228
void ebbrt::IxgbeDriverRep::Send(std::unique_ptr<IOBuf> buf, PacketInfo pinfo) {
181229
bool ip_cksum = false;
182230
bool tcpudp_cksum = false;
183231
uint64_t data;
184232
size_t len, count;
185-
int mcore = (int)Cpu::GetMine();
233+
uint32_t mcore = static_cast<uint32_t>(Cpu::GetMine());
234+
235+
#ifdef STATS_EN
236+
ixgmq_.stat_num_send ++;
237+
#endif
186238

187239
// TODO threshold for triggering reclaim tx buffers
188240
#ifndef TX_HEAD_WB
@@ -765,6 +817,7 @@ void ebbrt::IxgbeDriver::WritePsrtypeZero(uint32_t n) {
765817
// 4*n, n=0...31; RW)
766818
void ebbrt::IxgbeDriver::WriteReta(uint32_t n, uint32_t m) {
767819
bar0_.Write32(0x0EB00 + 4 * n, m);
820+
ebbrt::kprintf("WriteReta(n=%d) = 0x%08X\n", n, m);
768821
}
769822

770823
// 8.2.3.7.6 Receive Filter Control Register — RFCTL (0x05008; RW)
@@ -1276,6 +1329,7 @@ void ebbrt::IxgbeDriver::GlobalReset() {
12761329
**/
12771330
void ebbrt::IxgbeDriver::Init() {
12781331
uint64_t d_mac;
1332+
uint32_t ncore = static_cast<uint32_t>(Cpu::Count());
12791333

12801334
ebbrt::kprintf("%s ", __PRETTY_FUNCTION__);
12811335
bar0_.Map(); // allocate virtual memory
@@ -1419,6 +1473,10 @@ void ebbrt::IxgbeDriver::Init() {
14191473

14201474
#ifndef RSC_EN
14211475
WriteRxcsum(0x1 << 12); // IP payload checksum enable
1476+
#else
1477+
// note: PCSD: The Fragment Checksum and IP Identification fields are mutually exclusive with
1478+
// the RSS hash. Only one of the two options is reported in the Rx descriptor.
1479+
WriteRxcsum(0x2000);
14221480
#endif
14231481
// TODO RQTC
14241482

@@ -1432,10 +1490,48 @@ void ebbrt::IxgbeDriver::Init() {
14321490
WriteMpsar(i, 0x0);
14331491
}
14341492

1435-
// TODO RSSRK
1436-
1437-
for (auto i = 0; i < 32; i++) {
1438-
WriteReta(i, 0x0);
1493+
// RSSRK - random seeds taken from Linux
1494+
WriteRssrk(0, 0xA38DD80F);
1495+
WriteRssrk(1, 0xD107C3DC);
1496+
WriteRssrk(2, 0x8CEB19C4);
1497+
WriteRssrk(3, 0xA41E1B6B);
1498+
WriteRssrk(4, 0xB7218638);
1499+
WriteRssrk(5, 0x6B8B6155);
1500+
WriteRssrk(6, 0xDC8D08B5);
1501+
WriteRssrk(7, 0xD2E8684B);
1502+
WriteRssrk(8, 0xECEF8417);
1503+
WriteRssrk(9, 0xE56C84D5);
1504+
1505+
// Fill in RSS redirection table (128 entries), sets which core the lowest 7 bits of hashed output goes to
1506+
// hacky atm
1507+
for (auto i = 0; i < 32; i += 4) {
1508+
// all route to core 0
1509+
if(ncore == 1) {
1510+
WriteReta(i, 0x0000000);
1511+
WriteReta(i+1, 0x0000000);
1512+
WriteReta(i+2, 0x0000000);
1513+
WriteReta(i+3, 0x0000000);
1514+
} else if(ncore == 2) {
1515+
WriteReta(i, 0x1010100);
1516+
WriteReta(i+1, 0x1010100);
1517+
WriteReta(i+2, 0x1010100);
1518+
WriteReta(i+3, 0x1010100);
1519+
} else if(ncore == 4) {
1520+
WriteReta(i, 0x3020100);
1521+
WriteReta(i+1, 0x3020100);
1522+
WriteReta(i+2, 0x3020100);
1523+
WriteReta(i+3, 0x3020100);
1524+
} else if(ncore == 8) {
1525+
WriteReta(i, 0x3020100);
1526+
WriteReta(i+1, 0x7060504);
1527+
WriteReta(i+2, 0x3020100);
1528+
WriteReta(i+3, 0x7060504);
1529+
} else {
1530+
WriteReta(i, 0x3020100);
1531+
WriteReta(i+1, 0x7060504);
1532+
WriteReta(i+2, 0xB0A0908);
1533+
WriteReta(i+3, 0xF0E0D0C);
1534+
}
14391535
}
14401536

14411537
for (auto i = 0; i < 128; i++) {
@@ -1486,7 +1582,8 @@ void ebbrt::IxgbeDriver::Init() {
14861582
for (auto i = 1; i < 8; i++) {
14871583
WriteRxpbsize(i, 0x0);
14881584
}
1489-
WriteMrqc(0x0);
1585+
WriteMrqc(0x330001);
1586+
14901587
WritePfqde(0x0);
14911588
WriteRtrup2tc(0x0);
14921589
WriteMflcn(0x0 << 2);
@@ -1570,6 +1667,8 @@ void ebbrt::IxgbeDriver::SetupMultiQueue(uint32_t i) {
15701667
WritePsrtype(i, 0x1 << 4); // Split received TCP packets after TCP header.
15711668
#endif
15721669

1670+
// In NON-IOV, only psrtype[0] is used
1671+
WritePsrtype(0, 0x40001330);
15731672
// Set head and tail pointers
15741673
WriteRdt_1(i, 0x0);
15751674
WriteRdh_1(i, 0x0);
@@ -1583,6 +1682,8 @@ void ebbrt::IxgbeDriver::SetupMultiQueue(uint32_t i) {
15831682
// setup RX interrupts for queue i
15841683
dev_.SetMsixEntry(i, rcv_vector, ebbrt::Cpu::GetByIndex(i)->apic_id());
15851684

1685+
ebbrt::kprintf("Core %d: BSIZEPACKET=%d bytes NTXDESCS=%d NRXDESCS=%d ITR_INTERVAL=%dus RCV_VECTOR=%d APIC_ID=%d \n", i, RXBUFSZ, NTXDESCS, NRXDESCS, (int) (IxgbeDriver::ITR_INTERVAL * 2), (int)rcv_vector, (int)(ebbrt::Cpu::GetByIndex(i)->apic_id()));
1686+
15861687
// don't set up interrupts for tx since we have head writeback??
15871688
auto qn = i / 2; // put into correct IVAR
15881689

@@ -1597,7 +1698,7 @@ void ebbrt::IxgbeDriver::SetupMultiQueue(uint32_t i) {
15971698

15981699
// must be greater than rsc delay
15991700
// WriteEitr(i, 0x80 << 3); // 7 * 2us = 14 us
1600-
WriteEitr(i, (IxgbeDriver::ITR_INTERVAL << 3));
1701+
WriteEitr(i, (IxgbeDriver::ITR_INTERVAL << 3) | IXGBE_EITR_CNT_WDIS);
16011702

16021703
// 7.3.1.4 - Note that there are no EIAC(1)...EIAC(2) registers.
16031704
// The hardware setting for interrupts 16...63 is always auto clear.
@@ -1880,7 +1981,9 @@ uint32_t ebbrt::IxgbeDriverRep::GetRxBuf(uint32_t* len, uint64_t* bAddr,
18801981

18811982
// bump head ptr
18821983
ixgmq_.rx_head_ = (ixgmq_.rx_head_ + 1) % ixgmq_.rx_size_;
1883-
1984+
#ifdef STATS_EN
1985+
ixgmq_.stat_num_rx ++;
1986+
#endif
18841987
return 0;
18851988
}
18861989
#endif
@@ -1896,7 +1999,9 @@ void ebbrt::IxgbeDriverRep::ReceivePoll() {
18961999
uint32_t count;
18972000
uint32_t rnt;
18982001
process_rsc = false;
1899-
2002+
#ifdef STATS_EN
2003+
ixgmq_.stat_num_itr ++;
2004+
#endif
19002005
rxflag = 0;
19012006
count = 0;
19022007
rnt = 0;

src/native/IxgbeDriver.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@
1818
#include "Pci.h"
1919
#include "Pfn.h"
2020
#include "SlabAllocator.h"
21+
#include "Perf.h"
2122

2223
// Receive Side Scaling (RSC) enabled
2324
//#define RSC_EN
2425
// Direct Cache Access (DCA) enabled
2526
//#define DCA_ENABLE
26-
//// Transmit Header Writeback enabled
27-
#define TX_HEAD_WB
27+
// Transmit Header Writeback enabled
28+
//#define TX_HEAD_WB
29+
30+
// Collect Statistics Flag
31+
#define STATS_EN
2832

2933
namespace ebbrt {
3034

@@ -214,6 +218,20 @@ class IxgbeDriver : public EthernetDevice {
214218
#else
215219
size_t tx_head_;
216220
#endif
221+
222+
// stats
223+
uint64_t stat_num_itr{0};
224+
uint64_t stat_num_send{0};
225+
uint64_t stat_num_rx{0};
226+
uint64_t stat_num_tx{0};
227+
228+
bool stat_perf{false};
229+
ebbrt::perf::PerfCounter perfCycles;
230+
ebbrt::perf::PerfCounter perfInst;
231+
ebbrt::perf::PerfCounter perfLLC_ref;
232+
ebbrt::perf::PerfCounter perfLLC_miss;
233+
ebbrt::perf::PerfCounter perfTLB_store_miss;
234+
ebbrt::perf::PerfCounter perfTLB_load_miss;
217235
};
218236

219237
private:
@@ -364,6 +382,10 @@ class IxgbeDriver : public EthernetDevice {
364382
void WriteDtxmxszrq(uint32_t m);
365383
void WriteMflcn(uint32_t m);
366384
void WriteReta(uint32_t n, uint32_t m);
385+
void WriteRssrk(uint32_t n, uint32_t m) {
386+
kassert(n < 10);
387+
bar0_.Write32(0x0EB80 + 4 * n, m);
388+
}
367389

368390
void WritePsrtypeZero(uint32_t n);
369391

@@ -426,6 +448,8 @@ class IxgbeDriver : public EthernetDevice {
426448
uint32_t GetRxBuf(uint32_t* len, uint64_t* bAddr);
427449
void SendPacket(uint32_t n);
428450

451+
// dump per core stats if STATS_EN
452+
void DumpStats();
429453
e10k_queue_t& GetQueue() const { return *ixgq; }
430454

431455
e10Kq& GetMultiQueue(size_t index) const { return *ixgmq[index]; }

src/native/Net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct PacketInfo {
4646
uint16_t gso_size{0};
4747
uint16_t csum_start{0};
4848
uint16_t csum_offset{0};
49+
bool get_stats{false};
4950
};
5051

5152
class EthernetDevice {

src/native/NetIcmp.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ void ebbrt::NetworkManager::Interface::ReceiveIcmp(
4848

4949
PacketInfo pinfo;
5050
pinfo.flags = 0;
51-
51+
// hijacking ping to dump ixgbe statistics
52+
pinfo.get_stats = true;
5253
#ifdef __EBBRT_ENABLE_BAREMETAL_NIC__
5354
// hardware ip checksum offload
5455
pinfo.flags |= PacketInfo::kNeedsIpCsum;

0 commit comments

Comments
 (0)