On Wed, Oct 20, 2010 at 09:06:54AM -0700, Hefty, Sean wrote: > This contains both. A wire structure was added to libibverbs to > support librdmacm, which doesn't depend on umad. There are probably > only a few of structures that make sense as part of ibverbs - path > record and maybe multicast record. But, we'd have to get agreement > that umad should depend on ibverbs, or we'll always have duplicate > definitions.
Duplication doesn't concern me too much, as long as the structures are cast compatible it doesn't matter too much, there is nothing in verbs that uses the type, for instance? I think umad should depend on ibverbs (and use ibv_context to open the device, but that is another subject), and I think the *structures* should not have a ABI dependency on umad - static inlines and structure definitions. So you can compile against it without a link time dependency. This would let rdmacm use the structures, just have to compile libumad first. > Jason, can you share a portion of the final output looks like for your > codegen? Well, my codegen is tailored to what I've been doing. I would not use this approach to target C code, you need to use macros instead of templates, etc, etc. But that doesn't matter too much, you can codegen whatever you want, be it mad_get_field, or pack/unpack or the non-bitfield approach in ib_types.h. I have something in mind for C that is a combination of bitfields and the 1-byte=1-bit structure map technique. I'd codegen both host-endian overlays and network endian overlays. There is good reason for both, IMHO. [This email is so long already, I can outline my thoughts on this seperately if you are interested] What I've done has great properties, it is very difficult to make an endian error using it, and it has zero overhead on BE machines. /* [15.2.5.16] Information on paths through the subnet */ struct SAPathRecord { enum { attributeID = 0x35 }; uint32_t rsv0; uint32_t rsv1; struct HdrIPv6Addr DGID; struct HdrIPv6Addr SGID; uint16_t DLID; uint16_t SLID; uint32_t rawTraffic:1; uint32_t rsv2:3; uint32_t flowLabel:20; uint32_t hopLimit:8; uint8_t TClass; uint8_t reversible:1; uint8_t numbPath:7; uint16_t PKey; uint16_t rsv3:12; uint16_t SL:4; uint8_t MTUSelector:2; uint8_t MTU:6; uint8_t rateSelector:2; uint8_t rate:6; uint8_t packetLifeTimeSelector:2; uint8_t packetLifeTime:6; uint8_t preference; uint16_t rsv4; uint32_t rsv5; }; This is a host-endian bitfield overlay. Two are output, this is the host == BE version, the host == LE version is re-ordered: uint32_t hopLimit:8; uint32_t flowLabel:20; uint32_t rsv2:3; uint32_t rawTraffic:1; etc. The neat thing about the codegen is that is analyzes the arrangement to choose an optimal basic type. Ie TClass is not a bitfield, but hopLimit is because flowLabel spans a 16 bit quantity. This helps avoid any bit slicing code overheads by letting the compiler produce short and byte loads whenever possible. Use is sort of like: uint32_t madBuf[256/4]; for (int I = 0; I != 64; I++) madBuf[I] = ntohl(madBuf[I]); SAPathRecord *pr = madBuf; pr.DLID = 1; pr.SLID = 2; pr.TClss = 3; for (int I = 0; I != 64; I++) madBuf[I] = htonl(madBuf[I]); This avoids all ntoh/hton on types <= 32, and completely avoids all overhead on BE machines (which is important for me). In most of my code I stick the swap in the packet RX/TX path. The down side is that byte arrays, 64 bits and GIDs get messed up, but those are compartively rare. With the network endian overlays those 3 things are OK but lot of stuff like flowlabel is hoplessly messed up (need a ntoh20bits() function). I think both arrangements are useful.. The codgen uses C++ templates and anonymous unions to fix up some of the ugly stuff in the spec, like the byte arrays and the different labels for the MADHeaders in some cases.. These are special cases in the script. /* [14.2.1.2] SMP Format - Direct Routed */ struct SMPFormatDirected { enum { mgmtClass = 0x81 }; union { struct MADHeader MADHeader; struct { uint32_t MADHeader1; uint16_t D:1; uint16_t status:15; uint8_t hopPointer; uint8_t hopCount; uint32_t MADHeader2[4]; }; }; struct IBA64bit MKey; uint16_t drSLID; uint16_t drDLID; uint32_t rsv0[7]; uint32_t data[16]; IBABitFieldArray<8,64> initialPath; IBABitFieldArray<8,64> returnPath; }; Or the 3 bit wide arrays in PMPortSamplesCtl (so gross): /* [16.1.3.2] Port Performance Data Sampling Control */ struct PMPortSamplesCtl { enum { attributeID = 0x10 }; uint8_t opCode; uint8_t portSelect; uint8_t tick; uint8_t rsv0:5; uint8_t counterWidth:3; union { IBABitFieldArray<3,15,CounterMaskTraits> counterMask; struct { uint32_t rsv1:2; uint32_t counterMask0:3; uint32_t counterMask1:3; uint32_t counterMask2:3; uint32_t counterMask3:3; uint32_t counterMask4:3; uint32_t counterMask5:3; uint32_t counterMask6:3; uint32_t counterMask7:3; uint32_t counterMask8:3; uint32_t counterMask9:3; uint16_t rsv2:1; uint16_t counterMask10:3; uint16_t counterMask11:3; uint16_t counterMask12:3; uint16_t counterMask13:3; uint16_t counterMask14:3; uint8_t sampleMechanisms; uint8_t rsv3:6; uint8_t sampleStatus:2; }; }; The counterMask template's operator [] magically inlines the right code for foo.counterMask[x] - again this is all about reducing the possibility for coding error through automation. Last time this was brought up Roland mentioned he thought the codegen in gcc was poor for bitfields, I saw something recently that seems to indicate bitfields are similar/better than slicing: http://lwn.net/Articles/406067/ > Currently, I'd be happy just starting by having things like the mgmt > classes, methods, attribute IDs, status values, common mad header, > rmpp header, and sa header listed in a single place. Eventually, I > need the CM MADs defined, which aren't available AFAICT. The main data I lack is constants for things like error codes in obscure mads and so forth. You can codegen things like the componetMask constants quiet easially, etc. Since the database annotates structure arrangements and attribute IDs pretty well the codegen also produces an any-mad printer function with considerable field decoding. This is incredibly useful for debugging. ie: void print(const CMMRA & S, const char *prefix) { const uint32_t *p = reinterpret_cast < const uint32_t * >(&S); printf("%sGMP : %08x LCID=%u\n", prefix, *p++, (unsigned int) S.LCID); printf("%sGMP : %08x RCID=%u\n", prefix, *p++, (unsigned int) S.RCID); printf ("%sGMP : %08x messageMRAed=%u rsv0=%u serviceTimeout=%u rsv1=%u rsv2=%u\n", prefix, *p++, (unsigned int) S.messageMRAed, (unsigned int) S.rsv0, (unsigned int) S.serviceTimeout, (unsigned int) S.rsv1, (unsigned int) S.rsv2); for (unsigned int i = 0; i < 1760 / 32; i++) printf("%sGMP : %08x %11s[%2u]=%u\n", prefix, *p++, i == 0 ? "privateData" : "", i, S.privateData[i]); } This code gen is 500 lines of perl for the structs and another 350 for the printer code. > ib_types uses a lot of typedefs and #defines, so we may be able to > use those to provide backwards compatability. Maybe? I don't know.. To me the most important thing is to have a uniform conversion of what is in the spec to code, and from there if API preserving wrappers are possible then great, otherwise.. ? A big quibble I have with the naming in ibtypes is I think that network endian constants are a mistake. Very confusing. As far as Windows goes.. The great thing about codegen is you can codegen anything :) As long as the Windows compiler behaves predictably, we can codegen bitfields for it. There are only two possible ways to lay out bitfields (high bit first or low bit first) and the ABI specifies it. Linux ELF arm, ia32, ia64, pcc, mips 32/64 at least all use the same layout. Jason -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html