Rust 当函数移动到结构上的方法时,#[inline]属性为什么会停止工作?

Rust 当函数移动到结构上的方法时,#[inline]属性为什么会停止工作?,rust,inline,Rust,Inline,我有一个功能get_screen,它是在main.rs的单独模块中指定的。它采用两个二维向量(一个是1920x1080,称为屏幕,另一个更大,称为世界),并将世界向量的一部分映射到屏幕向量。这是我第一次制作时的函数签名: pub fn get_screen( screen: &mut Vec<Vec<[u8; 4]>>, world: &Vec<Vec<Chunk>>, camera_coords: (isi

我有一个功能
get_screen
,它是在main.rs的单独模块中指定的。它采用两个二维向量(一个是1920x1080,称为
屏幕
,另一个更大,称为
世界
),并将
世界
向量的一部分映射到
屏幕
向量。这是我第一次制作时的函数签名:

pub fn get_screen(
    screen: &mut Vec<Vec<[u8; 4]>>,
    world: &Vec<Vec<Chunk>>,
    camera_coords: (isize, isize),
    screen_width: usize,
    screen_height: usize,
    chunk_width: usize,
    chunk_height: usize,
)
然后执行时间增加回14毫秒。我曾尝试在Cargo.toml中启用
lto=true
,并切换到
#[内联(始终)]
来强制执行它,但编译器似乎拒绝按以前的方式优化此函数

我试图从结构中删除
get\u screen
方法,并像以前一样将其作为自己的函数运行,这似乎可以修复它,但前提是我没有从结构中传递任何内容。如果我尝试将
usize
world
结构传递到单独的
get_screen
函数,则执行时间从3ms增加到14ms

举一个例子来说明我的意思,如果我没有直接从
world
结构传递任何内容,而是在
world
中传递2D结构的克隆版本,以及硬编码的
chunk\u width
/
chunk\u height

gen::get_screen(
    &mut screen.buf,
    &cloned_world_data,
    camera_coords,
    SCREEN_WIDTH,
    SCREEN_HEIGHT,
    CHUNK_WIDTH,
    CHUNK_HEIGHT,
);
它以3.3毫秒的速度运行。当我直接从
world
结构传递
usize
字段
chunk\u width
/
chunk\u height
时:

gen::get_screen(
    &mut screen.buf,
    &cloned_world_data,
    camera_coords,
    SCREEN_WIDTH,
    SCREEN_HEIGHT,
    world.chunk_width,
    world.chunk_height,
);
跑步需要14.55毫秒

上面是什么?在使用my
World
struct时,如何让我的
get\u screen
函数内联编译?我希望能够将它作为一种方法重新添加到我的
World
struct中,而不是将其分开

下面是一个简单的例子:

use std::time::Instant;

const SCREEN_HEIGHT: usize = 1080; //528;
const SCREEN_WIDTH: usize = 1920; //960;
const CHUNK_WIDTH: usize = 256;
const CHUNK_HEIGHT: usize = 256;

const GEN_RANGE: isize = 25; //how far out to gen chunks

fn main() {
    let batch_size = 1_000;
    struct_test(batch_size);
    separate_test(batch_size);
}

fn struct_test(batch_size: u32) {
    let world = World::new(CHUNK_WIDTH, CHUNK_HEIGHT, GEN_RANGE); //generate world
    let mut screen = vec![vec!([0; 4]; SCREEN_WIDTH); SCREEN_HEIGHT];
    let camera_coords: (isize, isize) = (0, 0); //set camera location

    let start = Instant::now();
    for _ in 0..batch_size {
        get_screen(
            &mut screen,
            &world.data,
            camera_coords,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            world.chunk_width,
            world.chunk_height,
        ); //gets visible pixels from world as 2d vec
    }
    println!(
        "struct:   {:?} {:?}",
        start.elapsed(),
        start.elapsed() / batch_size
    );
}

fn separate_test(batch_size: u32) {
    let world = World::new(CHUNK_WIDTH, CHUNK_HEIGHT, GEN_RANGE); //generate world
    let cloned_world_data = world.data.clone();
    let mut screen = vec![vec!([0; 4]; SCREEN_WIDTH); SCREEN_HEIGHT];
    let camera_coords: (isize, isize) = (0, 0); //set camera location

    let start = Instant::now();
    for _ in 0..batch_size {
        get_screen(
            &mut screen,
            &cloned_world_data,
            camera_coords,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            CHUNK_WIDTH,
            CHUNK_HEIGHT,
        ); //gets visible pixels from world as 2d vec
    }
    println!(
        "separate: {:?} {:?}",
        start.elapsed(),
        start.elapsed() / batch_size
    );
}

///gets all visible pixels on screen relative camera position in world
#[inline(always)] //INLINE STOPPED WORKING??
pub fn get_screen(
    screen: &mut Vec<Vec<[u8; 4]>>,
    world: &Vec<Vec<Chunk>>,
    camera_coords: (isize, isize),
    screen_width: usize,
    screen_height: usize,
    chunk_width: usize,
    chunk_height: usize,
) {
    let camera = get_local_coords(&world, camera_coords, chunk_width, chunk_height); //gets loaded coords of camera in loaded chunks
    (camera.1 - screen_height as isize / 2..camera.1 + screen_height as isize / 2)
        .enumerate()
        .for_each(|(py, y)| {
            //for screen pixel index and particle in range of camera loaded y
            let (cy, ly) = get_local_pair(y, chunk_height); //calculate chunk y and inner y from loaded y
            if let Some(c_row) = world.get(cy) {
                //if chunk row at loaded chunk y exists
                (camera.0 - screen_width as isize / 2..camera.0 + screen_width as isize / 2)
                    .enumerate()
                    .for_each(|(px, x)| {
                        //for screen pixel index and particle in range of camera loaded x
                        let (cx, lx) = get_local_pair(x, chunk_width); //get loaded chunk x and inner x from loaded x
                        if let Some(c) = c_row.get(cx) {
                            screen[py][px] = c.data[ly][lx];
                        }
                        //if chunk in row then copy color of target particle in chunk
                        else {
                            screen[py][px] = [0; 4]
                        } //if target chunk doesn't exist color black
                    })
            } else {
                screen[py].iter_mut().for_each(|px| *px = [0; 4])
            } //if target chunk row doesn't exist color row black
        });
}

///calculates local coordinates in world vec from your global position
///returns negative if above/left of rendered area
pub fn get_local_coords(
    world: &Vec<Vec<Chunk>>,
    coords: (isize, isize),
    chunk_width: usize,
    chunk_height: usize,
) -> (isize, isize) {
    let (wx, wy) = world[0][0].chunk_coords; //gets coords of first chunk in rendered vec
    let lx = coords.0 - (wx * chunk_width as isize); //calculates local x coord based off world coords of first chunk
    let ly = (wy * chunk_height as isize) - coords.1; //calculates local y coord based off world coords of first chunk
    (lx, ly)
}

pub fn get_local_pair(coord: isize, chunk: usize) -> (usize, usize) {
    (coord as usize / chunk, coord as usize % chunk)
}

///contains chunk data
#[derive(Clone)]
pub struct Chunk {
    //world chunk object
    pub chunk_coords: (isize, isize), //chunk coordinates
    pub data: Vec<Vec<[u8; 4]>>,      //chunk Particle data
}

impl Chunk {
    ///generates chunk
    fn new(chunk_coords: (isize, isize), chunk_width: usize, chunk_height: usize) -> Self {
        let data = vec![vec!([0; 4]; chunk_width); chunk_height];
        Self { chunk_coords, data }
    }
}

pub struct World {
    pub data: Vec<Vec<Chunk>>,
    pub chunk_width: usize,
    pub chunk_height: usize,
}

impl World {
    pub fn new(chunk_width: usize, chunk_height: usize, gen_range: isize) -> Self {
        let mut data = Vec::new(); //creates empty vec to hold world
        for (yi, world_chunk_y) in (gen_range * -1..gen_range + 1).rev().enumerate() {
            //for y index, y in gen range counting down
            data.push(Vec::new()); //push new row
            for world_chunk_x in gen_range * -1..gen_range + 1 {
                //for chunk in gen range of row
                data[yi].push(Chunk::new(
                    (world_chunk_x, world_chunk_y),
                    chunk_width,
                    chunk_height,
                )); //gen new chunk and put it there
            }
        }
        Self {
            data,
            chunk_width,
            chunk_height,
        }
    }
}
使用std::time::Instant;
恒定屏幕高度:usize=1080//528;
恒定屏幕宽度:usize=1920//960;
const CHUNK_WIDTH:usize=256;
const CHUNK_HEIGHT:usize=256;
恒压范围:isize=25//到gen chunks还有多远
fn main(){
让批次大小=1_000;
结构测试(批量大小);
单独试验(批量);
}
fn结构测试(批量大小:u32){
let world=world::new(块宽度、块高度、根范围);//生成世界
让mut screen=vec![vec!([0;4];屏幕宽度;屏幕高度];
让摄影机协调:(isize,isize)=(0,0);//设置摄影机位置
让我们开始=瞬间::现在();
对于0.批次大小中的u{
获取屏幕(
&mut屏幕,
&世界数据,
摄像机坐标,
屏幕宽度,
屏幕高度,
world.chunk\u宽度,
世界。你的身高,
);//以2d矢量形式从世界获取可见像素
}
普林顿(
“结构:{:?}{:?}”,
start.appeased(),
start.appead()/批大小
);
}
fn单独试验(批量尺寸:u32){
let world=world::new(块宽度、块高度、根范围);//生成世界
让cloned_world_data=world.data.clone();
让mut screen=vec![vec!([0;4];屏幕宽度;屏幕高度];
让摄影机协调:(isize,isize)=(0,0);//设置摄影机位置
让我们开始=瞬间::现在();
对于0.批次大小中的u{
获取屏幕(
&mut屏幕,
&克隆的世界数据,
摄像机坐标,
屏幕宽度,
屏幕高度,
块的宽度,
身高,
);//以2d矢量形式从世界获取可见像素
}
普林顿(
“分开:{:?}{:?}”,
start.appeased(),
start.appead()/批大小
);
}
///获取屏幕上所有可见像素相对于世界上的相机位置
#[内联(始终)]//内联已停止工作??
pub fn get_屏幕(
屏幕:&mut Vec,
世界:&Vec,
摄像机坐标:(isize,isize),
屏幕宽度:usize,
屏幕高度:usize,
区块宽度:usize,
区块高度:使用,
) {
让camera=get_local_coords(&world,camera_coords,chunk_width,chunk_height);//以加载的块获取摄影机的加载坐标
(摄像头.1-屏幕高度为isize/2..摄像头.1+屏幕高度为isize/2)
.enumerate()
.对于每个(|(py,y)|{
//用于屏幕像素索引和摄影机加载y范围内的粒子
let(cy,ly)=获取_local_pair(y,chunk _height);//从加载的y计算chunk y和内部y
如果让一些(c_row)=世界得到(cy){
//如果加载的块y上存在块行
(camera.0-屏幕宽度为isize/2..camera.0+屏幕宽度为isize/2)
.enumerate()
.对于每一个(|(px,x)|{
//用于屏幕像素索引和摄影机加载x范围内的粒子
let(cx,lx)=获取_本地_对(x,块_宽度);//从加载的x获取加载的块x和内部x
如果让一些(c)=c_行获得(cx){
屏幕[py][px]=c.data[ly][lx];
}
//如果块位于行中,则复制块中目标粒子的颜色
否则{
屏幕[py][px]=[0;4]
}//如果目标块不存在,则颜色为黑色
})
}否则{
屏幕[py].iter_mut().for_each(|px |*px=[0;4])
}//如果目标区块行不存在,则颜色为黑色
});
}
///从全局位置计算世界向量中的局部坐标
///如果在渲染区域的上方/左侧,则返回负值
酒吧与当地合作(
世界:&Vec,
协调人:(伊西泽,伊西泽),
区块宽度:usize,
区块高度:使用,
)->(isize,isize){
let(wx,wy)=世界[0][0]。chunk_coords;//获取渲染向量中第一个块的坐标
设lx=coords.0-(wx*chunk_width as isize);//基于第一个块的非世界坐标计算局部x坐标
设ly=(wy*chunk\u高度为isize)-coords.1;//ca
use std::time::Instant;

const SCREEN_HEIGHT: usize = 1080; //528;
const SCREEN_WIDTH: usize = 1920; //960;
const CHUNK_WIDTH: usize = 256;
const CHUNK_HEIGHT: usize = 256;

const GEN_RANGE: isize = 25; //how far out to gen chunks

fn main() {
    let batch_size = 1_000;
    struct_test(batch_size);
    separate_test(batch_size);
}

fn struct_test(batch_size: u32) {
    let world = World::new(CHUNK_WIDTH, CHUNK_HEIGHT, GEN_RANGE); //generate world
    let mut screen = vec![vec!([0; 4]; SCREEN_WIDTH); SCREEN_HEIGHT];
    let camera_coords: (isize, isize) = (0, 0); //set camera location

    let start = Instant::now();
    for _ in 0..batch_size {
        get_screen(
            &mut screen,
            &world.data,
            camera_coords,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            world.chunk_width,
            world.chunk_height,
        ); //gets visible pixels from world as 2d vec
    }
    println!(
        "struct:   {:?} {:?}",
        start.elapsed(),
        start.elapsed() / batch_size
    );
}

fn separate_test(batch_size: u32) {
    let world = World::new(CHUNK_WIDTH, CHUNK_HEIGHT, GEN_RANGE); //generate world
    let cloned_world_data = world.data.clone();
    let mut screen = vec![vec!([0; 4]; SCREEN_WIDTH); SCREEN_HEIGHT];
    let camera_coords: (isize, isize) = (0, 0); //set camera location

    let start = Instant::now();
    for _ in 0..batch_size {
        get_screen(
            &mut screen,
            &cloned_world_data,
            camera_coords,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            CHUNK_WIDTH,
            CHUNK_HEIGHT,
        ); //gets visible pixels from world as 2d vec
    }
    println!(
        "separate: {:?} {:?}",
        start.elapsed(),
        start.elapsed() / batch_size
    );
}

///gets all visible pixels on screen relative camera position in world
#[inline(always)] //INLINE STOPPED WORKING??
pub fn get_screen(
    screen: &mut Vec<Vec<[u8; 4]>>,
    world: &Vec<Vec<Chunk>>,
    camera_coords: (isize, isize),
    screen_width: usize,
    screen_height: usize,
    chunk_width: usize,
    chunk_height: usize,
) {
    let camera = get_local_coords(&world, camera_coords, chunk_width, chunk_height); //gets loaded coords of camera in loaded chunks
    (camera.1 - screen_height as isize / 2..camera.1 + screen_height as isize / 2)
        .enumerate()
        .for_each(|(py, y)| {
            //for screen pixel index and particle in range of camera loaded y
            let (cy, ly) = get_local_pair(y, chunk_height); //calculate chunk y and inner y from loaded y
            if let Some(c_row) = world.get(cy) {
                //if chunk row at loaded chunk y exists
                (camera.0 - screen_width as isize / 2..camera.0 + screen_width as isize / 2)
                    .enumerate()
                    .for_each(|(px, x)| {
                        //for screen pixel index and particle in range of camera loaded x
                        let (cx, lx) = get_local_pair(x, chunk_width); //get loaded chunk x and inner x from loaded x
                        if let Some(c) = c_row.get(cx) {
                            screen[py][px] = c.data[ly][lx];
                        }
                        //if chunk in row then copy color of target particle in chunk
                        else {
                            screen[py][px] = [0; 4]
                        } //if target chunk doesn't exist color black
                    })
            } else {
                screen[py].iter_mut().for_each(|px| *px = [0; 4])
            } //if target chunk row doesn't exist color row black
        });
}

///calculates local coordinates in world vec from your global position
///returns negative if above/left of rendered area
pub fn get_local_coords(
    world: &Vec<Vec<Chunk>>,
    coords: (isize, isize),
    chunk_width: usize,
    chunk_height: usize,
) -> (isize, isize) {
    let (wx, wy) = world[0][0].chunk_coords; //gets coords of first chunk in rendered vec
    let lx = coords.0 - (wx * chunk_width as isize); //calculates local x coord based off world coords of first chunk
    let ly = (wy * chunk_height as isize) - coords.1; //calculates local y coord based off world coords of first chunk
    (lx, ly)
}

pub fn get_local_pair(coord: isize, chunk: usize) -> (usize, usize) {
    (coord as usize / chunk, coord as usize % chunk)
}

///contains chunk data
#[derive(Clone)]
pub struct Chunk {
    //world chunk object
    pub chunk_coords: (isize, isize), //chunk coordinates
    pub data: Vec<Vec<[u8; 4]>>,      //chunk Particle data
}

impl Chunk {
    ///generates chunk
    fn new(chunk_coords: (isize, isize), chunk_width: usize, chunk_height: usize) -> Self {
        let data = vec![vec!([0; 4]; chunk_width); chunk_height];
        Self { chunk_coords, data }
    }
}

pub struct World {
    pub data: Vec<Vec<Chunk>>,
    pub chunk_width: usize,
    pub chunk_height: usize,
}

impl World {
    pub fn new(chunk_width: usize, chunk_height: usize, gen_range: isize) -> Self {
        let mut data = Vec::new(); //creates empty vec to hold world
        for (yi, world_chunk_y) in (gen_range * -1..gen_range + 1).rev().enumerate() {
            //for y index, y in gen range counting down
            data.push(Vec::new()); //push new row
            for world_chunk_x in gen_range * -1..gen_range + 1 {
                //for chunk in gen range of row
                data[yi].push(Chunk::new(
                    (world_chunk_x, world_chunk_y),
                    chunk_width,
                    chunk_height,
                )); //gen new chunk and put it there
            }
        }
        Self {
            data,
            chunk_width,
            chunk_height,
        }
    }
}