From e53a8987247ac159b925ede1ad47e830efca7a0f Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Fri, 7 Nov 2025 15:26:01 +0000 Subject: [PATCH] nvidia(ctrla081): sync vGPU 19.x (R580) fields - There were a large number of changes that are backwards incompatible which necessitated separate structures to track these changes. - Thank you @rbqvq with https://github.com/rbqvq/vgpu_unlock-rs/commit/2b08855f80739ac75b0ca2528ef6b6b599a5086e for an initial version of this work! (#50) --- src/lib.rs | 160 +++++++++++++++++++++++++++++----- src/nvidia/ctrla081.rs | 193 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 315 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ece6372..e73bf01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,9 +51,9 @@ use crate::nvidia::ctrl2080bus::{Nv2080CtrlBusGetPciInfoParams, NV2080_CTRL_CMD_ use crate::nvidia::ctrl2080gpu::NV2080_CTRL_CMD_GPU_GET_INFOROM_OBJECT_VERSION; use crate::nvidia::ctrl9096::NV9096_CTRL_CMD_GET_ZBC_CLEAR_TABLE; use crate::nvidia::ctrla081::{ - NvA081CtrlCmdVgpuConfigGetMigrationCapParams, NvA081CtrlVgpuConfigGetVgpuTypeInfoParams, - NvA081CtrlVgpuInfo, NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP, - NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, + NvA081CtrlCmdVgpuConfigGetMigrationCapParams, NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525, + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580, NvA081CtrlVgpuInfoV525, NvA081CtrlVgpuInfoV580, + NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP, NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, }; use crate::nvidia::ctrla082::{ NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams, @@ -95,8 +95,8 @@ const DEFAULT_PROFILE_OVERRIDE_CONFIG_PATH: &str = "/etc/vgpu_unlock/profile_ove trait VgpuConfigLike { fn vgpu_type(&mut self) -> &mut u32; - fn vgpu_name(&mut self) -> &mut [u8; 32]; - fn vgpu_class(&mut self) -> &mut [u8; 32]; + fn vgpu_name(&mut self) -> &mut [u8]; + fn vgpu_class(&mut self) -> &mut [u8]; //fn vgpu_signature(&mut self) -> &mut [u8; 128]; fn license(&mut self) -> &mut [u8; 128]; fn max_instance(&mut self) -> &mut u32; @@ -126,6 +126,11 @@ trait VgpuConfigLike { } macro_rules! impl_trait_fn { + ($field:ident, [$t:ty; ..]) => { + fn $field(&mut self) -> &mut [$t] { + &mut self.$field[..] + } + }; ($field:ident, $t:ty) => { fn $field(&mut self) -> &mut $t { &mut self.$field @@ -147,8 +152,8 @@ macro_rules! impl_trait_fn_aligned { impl VgpuConfigLike for NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams { impl_trait_fn!(vgpu_type, u32); - impl_trait_fn!(vgpu_name, [u8; 32]); - impl_trait_fn!(vgpu_class, [u8; 32]); + impl_trait_fn!(vgpu_name, [u8; ..]); + impl_trait_fn!(vgpu_class, [u8; ..]); //impl_trait_fn!(vgpu_signature, [u8; 128]); impl_trait_fn!(license, [u8; 128]); impl_trait_fn!(max_instance, u32); @@ -183,10 +188,48 @@ impl VgpuConfigLike for NvA082CtrlCmdHostVgpuDeviceGetVgpuTypeInfoParams { //impl_trait_fn!(vgpu_extra_params, [u8]); } -impl VgpuConfigLike for NvA081CtrlVgpuInfo { +impl VgpuConfigLike for NvA081CtrlVgpuInfoV525 { impl_trait_fn!(vgpu_type, u32); - impl_trait_fn!(vgpu_name, [u8; 32]); - impl_trait_fn!(vgpu_class, [u8; 32]); + impl_trait_fn!(vgpu_name, [u8; ..]); + impl_trait_fn!(vgpu_class, [u8; ..]); + //impl_trait_fn!(vgpu_signature, [u8; 128]); + impl_trait_fn!(license, [u8; 128]); + impl_trait_fn!(max_instance, u32); + impl_trait_fn!(num_heads, u32); + impl_trait_fn!(max_resolution_x, u32); + impl_trait_fn!(max_resolution_y, u32); + impl_trait_fn!(max_pixels, u32); + impl_trait_fn!(frl_config, u32); + impl_trait_fn!(cuda_enabled, u32); + impl_trait_fn!(ecc_supported, u32); + impl_trait_fn!(gpu_instance_size => mig_instance_size, u32); + impl_trait_fn!(multi_vgpu_supported, u32); + impl_trait_fn_aligned!(vdev_id, u64); + impl_trait_fn_aligned!(pdev_id, u64); + + /* + fn profile_size(&mut self) -> Option<&mut u64> { + Some(&mut self.profile_size.0) + } + */ + + impl_trait_fn_aligned!(fb_length, u64); + impl_trait_fn_aligned!(mappable_video_size, u64); + impl_trait_fn_aligned!(fb_reservation, u64); + impl_trait_fn!(encoder_capacity, u32); + impl_trait_fn_aligned!(bar1_length, u64); + impl_trait_fn!(frl_enable, u32); + impl_trait_fn!(adapter_name, [u8; 64]); + impl_trait_fn!(adapter_name_unicode, [u16; 64]); + impl_trait_fn!(short_gpu_name_string, [u8; 64]); + impl_trait_fn!(licensed_product_name, [u8; 128]); + //impl_trait_fn!(vgpu_extra_params, [u8]); +} + +impl VgpuConfigLike for NvA081CtrlVgpuInfoV580 { + impl_trait_fn!(vgpu_type, u32); + impl_trait_fn!(vgpu_name, [u8; ..]); + impl_trait_fn!(vgpu_class, [u8; ..]); //impl_trait_fn!(vgpu_signature, [u8; 128]); impl_trait_fn!(license, [u8; 128]); impl_trait_fn!(max_instance, u32); @@ -264,12 +307,17 @@ struct VgpuProfileOverride { license_type: Option, } +fn check_size_log(name: &str, actual_size: usize, expected_size: usize) { + error!("Parameters size for {name} was {actual_size} bytes, expected {expected_size} bytes"); +} + +fn check_size_multiple_log(name: &str, actual_size: usize, expected_size: &[usize]) { + error!("Parameters size for {name} was {actual_size} bytes, expected one of {expected_size:?} bytes"); +} + fn check_size(name: &str, actual_size: usize, expected_size: usize) -> bool { if actual_size != expected_size { - error!( - "Parameters size for {} was {} bytes, expected {} bytes", - name, actual_size, expected_size - ); + check_size_log(name, actual_size, expected_size); false } else { @@ -277,6 +325,18 @@ fn check_size(name: &str, actual_size: usize, expected_size: usize) -> bool { } } +#[inline(always)] +fn check_size_raw(actual_size: usize, expected_size: usize) -> bool { + actual_size == expected_size +} + +#[inline(always)] +fn check_size_raw_multiple(actual_size: usize, expected_size: &[usize]) -> bool { + expected_size + .iter() + .any(|&expected_size| actual_size == expected_size) +} + /// # Safety /// /// This is actually unsafe since `ioctl` is variadic. All the `ioctl` calls in the @@ -337,6 +397,39 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - ) }; } + macro_rules! check_size_raw { + ($expected_type:ty) => { + check_size_raw( + io_data.params_size as usize, + mem::size_of::<$expected_type>(), + ) + }; + ($expected_type:ty, other: [$($expected_size:expr),* $(,)?]) => { + check_size_raw_multiple( + io_data.params_size as usize, + &[ + mem::size_of::<$expected_type>(), + $($expected_size,)* + ], + ) + }; + } + macro_rules! check_size_log { + ( + name: $name:ident, + types: [$($expected_type:ty),* $(,)?], + other: [$($expected_size:expr),* $(,)?] $(,)? + ) => { + check_size_multiple_log( + stringify!($name), + io_data.params_size as usize, + &[ + $(mem::size_of::<$expected_type>(),)* + $($expected_size,)* + ], + ) + } + } match io_data.cmd { NV2080_CTRL_CMD_BUS_GET_PCI_INFO @@ -450,16 +543,16 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - *LAST_MDEV_UUID.lock() = Some(params.vgpu_name); } NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO => { - // 18.0 driver sends larger struct with size 5232 bytes, 17.0 driver sends larger struct with size 5096 bytes. Only extra members added at the end, - // nothing in between or changed, so accessing the larger struct is "safe" - if io_data.params_size == 5232 - || io_data.params_size == 5096 - || check_size!( - NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, - NvA081CtrlVgpuConfigGetVgpuTypeInfoParams + if + // 18.0 driver sends larger struct with size 5232 bytes, 17.0 driver sends a + // larger struct with size 5096 bytes. Only extra members added at the end, + // nothing earlier changed in the structure, so accessing the struct is "safe". + check_size_raw!( + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525, + other: [5232, 5096] ) { - let params: &mut NvA081CtrlVgpuConfigGetVgpuTypeInfoParams = + let params: &mut NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525 = &mut *io_data.params.cast(); info!("{:#?}", params); @@ -467,6 +560,29 @@ pub unsafe extern "C" fn ioctl(fd: RawFd, request: c_ulong, argp: *mut c_void) - error!("Failed to apply profile override"); return -1; } + } else if + // 19.0 driver sends much larger structure than 18.x and prior with expanded + // fields. This necessitated a separate structure as it was no longer + // backwards compatible. + check_size_raw!(NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580) + { + let params: &mut NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580 = + &mut *io_data.params.cast(); + info!("{:#?}", params); + + if !handle_profile_override(&mut params.vgpu_type_info) { + error!("Failed to apply profile override"); + return -1; + } + } else { + check_size_log! { + name: NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO, + types: [ + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525, + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580, + ], + other: [5232, 5096], + }; } } NVA082_CTRL_CMD_HOST_VGPU_DEVICE_GET_VGPU_TYPE_INFO diff --git a/src/nvidia/ctrla081.rs b/src/nvidia/ctrla081.rs index 2548cbf..a53521a 100644 --- a/src/nvidia/ctrla081.rs +++ b/src/nvidia/ctrla081.rs @@ -1,24 +1,28 @@ -///! Sourced from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrla081.h +///! Sourced from: +///! 525: https://github.com/NVIDIA/open-gpu-kernel-modules/blob/758b4ee8189c5198504cb1c3c5bc29027a9118a3/src/common/sdk/nvidia/inc/ctrl/ctrla081.h +///! 580: https://github.com/NVIDIA/open-gpu-kernel-modules/blob/307159f2623d3bf45feb9177bd2da52ffbc5ddf9/src/common/sdk/nvidia/inc/ctrl/ctrla081.h use std::fmt; use super::ctrl2080gpu::{NV2080_GPU_MAX_NAME_STRING_LENGTH, NV_GRID_LICENSE_INFO_MAX_LENGTH}; -use crate::format::{CStrFormat, HexFormat, HexFormatSlice, WideCharFormat}; +use crate::format::{CStrFormat, HexFormat, HexFormatSlice, StraightFormat, WideCharFormat}; use crate::utils::AlignedU64; -pub const NVA081_VGPU_STRING_BUFFER_SIZE: usize = 32; +pub const NVA081_VGPU_STRING_BUFFER_SIZE_V525: usize = 32; +pub const NVA081_VGPU_STRING_BUFFER_SIZE_V580: usize = 64; pub const NVA081_VGPU_SIGNATURE_SIZE: usize = 128; pub const NVA081_EXTRA_PARAMETERS_SIZE: usize = 1024; -// pub const NVA081_MAX_VGPU_PER_PGPU: usize = 32; +// pub const NVA081_MAX_VGPU_PER_PGPU_V525: usize = 32; +pub const NVA081_MAX_VGPU_PER_PGPU_V580: usize = 48; /// See `NVA081_CTRL_VGPU_CONFIG_INFO` // Set `align(8)` for `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` #[repr(C, align(8))] -pub struct NvA081CtrlVgpuInfo { +pub struct NvA081CtrlVgpuInfoV525 { pub vgpu_type: u32, - pub vgpu_name: [u8; NVA081_VGPU_STRING_BUFFER_SIZE], - pub vgpu_class: [u8; NVA081_VGPU_STRING_BUFFER_SIZE], + pub vgpu_name: [u8; NVA081_VGPU_STRING_BUFFER_SIZE_V525], + pub vgpu_class: [u8; NVA081_VGPU_STRING_BUFFER_SIZE_V525], pub vgpu_signature: [u8; NVA081_VGPU_SIGNATURE_SIZE], pub license: [u8; NV_GRID_LICENSE_INFO_MAX_LENGTH], pub max_instance: u32, @@ -69,15 +73,73 @@ pub struct NvA081CtrlVgpuInfo { // pub heterogeneousPlacementIds: [u32; NVA081_MAX_VGPU_PER_PGPU], } +/// See `NVA081_CTRL_VGPU_CONFIG_INFO` +// Set `align(8)` for `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` +#[repr(C, align(8))] +pub struct NvA081CtrlVgpuInfoV580 { + pub vgpu_type: u32, + pub vgpu_name: [u8; NVA081_VGPU_STRING_BUFFER_SIZE_V580], + pub vgpu_class: [u8; NVA081_VGPU_STRING_BUFFER_SIZE_V580], + pub vgpu_signature: [u8; NVA081_VGPU_SIGNATURE_SIZE], + pub license: [u8; NV_GRID_LICENSE_INFO_MAX_LENGTH], + pub max_instance: u32, + pub num_heads: u32, + pub max_resolution_x: u32, + pub max_resolution_y: u32, + pub max_pixels: u32, + pub frl_config: u32, + pub cuda_enabled: u32, + pub ecc_supported: u32, + pub gpu_instance_size: u32, + pub multi_vgpu_supported: u32, + pub vdev_id: AlignedU64, + pub pdev_id: AlignedU64, + pub profile_size: AlignedU64, + pub fb_length: AlignedU64, + pub gsp_heap_size: AlignedU64, + pub fb_reservation: AlignedU64, + pub mappable_video_size: AlignedU64, + pub encoder_capacity: u32, + pub bar1_length: AlignedU64, + pub frl_enable: u32, + pub adapter_name: [u8; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub adapter_name_unicode: [u16; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub short_gpu_name_string: [u8; NV2080_GPU_MAX_NAME_STRING_LENGTH], + pub licensed_product_name: [u8; NV_GRID_LICENSE_INFO_MAX_LENGTH], + pub vgpu_extra_params: [u32; NVA081_EXTRA_PARAMETERS_SIZE], + pub ftrace_enable: u32, + pub gpu_direct_supported: u32, + pub nvlink_p2p_supported: u32, + pub max_instance_per_gi: u32, + pub multi_vgpu_exclusive: u32, + pub exclusive_type: u32, + pub exclusive_size: u32, + pub gpu_instance_profile_id: u32, + pub placement_size: u32, + pub homogeneous_placement_count: u32, + pub homogeneous_placement_ids: [u32; NVA081_MAX_VGPU_PER_PGPU_V580], + pub heterogeneous_placement_count: u32, + pub heterogeneous_placement_ids: [u32; NVA081_MAX_VGPU_PER_PGPU_V580], +} + pub const NVA081_CTRL_CMD_VGPU_CONFIG_GET_VGPU_TYPE_INFO: u32 = 0xa0810103; /// This RM control command is used starting in vGPU version 15.0 (525.60.12). /// /// See `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` #[repr(C)] -pub struct NvA081CtrlVgpuConfigGetVgpuTypeInfoParams { +pub struct NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525 { pub vgpu_type: u32, - pub vgpu_type_info: NvA081CtrlVgpuInfo, + pub vgpu_type_info: NvA081CtrlVgpuInfoV525, +} + +/// This RM control command is used starting in vGPU version 15.0 (525.60.12). +/// +/// See `NVA081_CTRL_VGPU_CONFIG_GET_VGPU_TYPE_INFO_PARAMS` +#[repr(C)] +pub struct NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580 { + pub vgpu_type: u32, + pub vgpu_type_info: NvA081CtrlVgpuInfoV580, } pub const NVA081_CTRL_CMD_VGPU_CONFIG_GET_MIGRATION_CAP: u32 = 0xa0810112; @@ -88,7 +150,7 @@ pub struct NvA081CtrlCmdVgpuConfigGetMigrationCapParams { pub migration_cap: u8, } -impl fmt::Debug for NvA081CtrlVgpuInfo { +impl fmt::Debug for NvA081CtrlVgpuInfoV525 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let vgpu_signature = if self.vgpu_signature[..].iter().any(|&x| x != 0) { &self.vgpu_signature[..] @@ -101,7 +163,7 @@ impl fmt::Debug for NvA081CtrlVgpuInfo { &[] }; - f.debug_struct("NvA081CtrlVgpuInfo") + f.debug_struct("NvA081CtrlVgpuInfoV525") .field("vgpu_type", &self.vgpu_type) .field("vgpu_name", &CStrFormat(&self.vgpu_name)) .field("vgpu_class", &CStrFormat(&self.vgpu_class)) @@ -152,9 +214,99 @@ impl fmt::Debug for NvA081CtrlVgpuInfo { } } -impl fmt::Debug for NvA081CtrlVgpuConfigGetVgpuTypeInfoParams { +impl fmt::Debug for NvA081CtrlVgpuInfoV580 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("NvA081CtrlVgpuConfigGetVgpuTypeInfoParams") + let vgpu_signature = if self.vgpu_signature[..].iter().any(|&x| x != 0) { + &self.vgpu_signature[..] + } else { + &[] + }; + let vgpu_extra_params = if self.vgpu_extra_params[..].iter().any(|&x| x != 0) { + &self.vgpu_extra_params[..] + } else { + &[] + }; + + f.debug_struct("NvA081CtrlVgpuInfoV580") + .field("vgpu_type", &self.vgpu_type) + .field("vgpu_name", &CStrFormat(&self.vgpu_name)) + .field("vgpu_class", &CStrFormat(&self.vgpu_class)) + .field("vgpu_signature", &HexFormatSlice(vgpu_signature)) + .field("license", &CStrFormat(&self.license)) + .field("max_instance", &self.max_instance) + .field("num_heads", &self.num_heads) + .field("max_resolution_x", &self.max_resolution_x) + .field("max_resolution_y", &self.max_resolution_y) + .field("max_pixels", &self.max_pixels) + .field("frl_config", &self.frl_config) + .field("cuda_enabled", &self.cuda_enabled) + .field("ecc_supported", &self.ecc_supported) + .field("gpu_instance_size", &self.gpu_instance_size) + .field("multi_vgpu_supported", &self.multi_vgpu_supported) + .field("vdev_id", &HexFormat(self.vdev_id)) + .field("pdev_id", &HexFormat(self.pdev_id)) + .field("profile_size", &HexFormat(self.profile_size)) + .field("fb_length", &HexFormat(self.fb_length)) + .field("gsp_heap_size", &HexFormat(self.gsp_heap_size)) + .field("fb_reservation", &HexFormat(self.fb_reservation)) + .field("mappable_video_size", &HexFormat(self.mappable_video_size)) + .field("encoder_capacity", &HexFormat(self.encoder_capacity)) + .field("bar1_length", &HexFormat(self.bar1_length)) + .field("frl_enable", &self.frl_enable) + .field("adapter_name", &CStrFormat(&self.adapter_name)) + .field( + "adapter_name_unicode", + &WideCharFormat(&self.adapter_name_unicode), + ) + .field( + "short_gpu_name_string", + &CStrFormat(&self.short_gpu_name_string), + ) + .field( + "licensed_product_name", + &CStrFormat(&self.licensed_product_name), + ) + .field("vgpu_extra_params", &HexFormatSlice(vgpu_extra_params)) + .field("ftrace_enable", &self.ftrace_enable) + .field("gpu_direct_supported", &self.gpu_direct_supported) + .field("nvlink_p2p_supported", &self.nvlink_p2p_supported) + .field("max_instance_per_gi", &self.max_instance_per_gi) + .field("multi_vgpu_exclusive", &self.multi_vgpu_exclusive) + .field("exclusive_type", &self.exclusive_type) + .field("exclusive_size", &self.exclusive_size) + .field("gpu_instance_profile_id", &self.gpu_instance_profile_id) + .field( + "homogeneous_placement_count", + &self.homogeneous_placement_count, + ) + .field( + "homogeneous_placement_ids", + &StraightFormat(&self.homogeneous_placement_ids[..]), + ) + .field( + "heterogeneous_placement_count", + &self.heterogeneous_placement_count, + ) + .field( + "heterogeneous_placement_ids", + &StraightFormat(&self.heterogeneous_placement_ids[..]), + ) + .finish() + } +} + +impl fmt::Debug for NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525") + .field("vgpu_type", &self.vgpu_type) + .field("vgpu_type_info", &self.vgpu_type_info) + .finish() + } +} + +impl fmt::Debug for NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580") .field("vgpu_type", &self.vgpu_type) .field("vgpu_type_info", &self.vgpu_type_info) .finish() @@ -165,14 +317,23 @@ impl fmt::Debug for NvA081CtrlVgpuConfigGetVgpuTypeInfoParams { mod test { use std::mem; - use super::{NvA081CtrlVgpuConfigGetVgpuTypeInfoParams, NvA081CtrlVgpuInfo}; + use super::{ + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV525, + NvA081CtrlVgpuConfigGetVgpuTypeInfoParamsV580, NvA081CtrlVgpuInfoV525, + NvA081CtrlVgpuInfoV580, + }; #[test] fn verify_sizes() { - assert_eq!(mem::size_of::(), 0x1358); + assert_eq!(mem::size_of::(), 0x1358); + assert_eq!(mem::size_of::(), 0x1528); assert_eq!( - mem::size_of::(), + mem::size_of::(), 0x1360 ); + assert_eq!( + mem::size_of::(), + 0x1530 + ); } }