mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
WIP: add initial intel xe/i915 support
This commit is contained in:
parent
08a3d5b90e
commit
22bf7257f8
@ -545,6 +545,10 @@ impl AmdGpuController {
|
||||
&& STEAM_DECK_IDS.contains(&info.device_pci_info.model_id.as_str())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_driver(&self) -> &str {
|
||||
self.handle.get_driver()
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuController for AmdGpuController {
|
||||
@ -572,19 +576,23 @@ impl GpuController for AmdGpuController {
|
||||
self.handle.get_path()
|
||||
}
|
||||
|
||||
fn get_info(&self) -> DeviceInfo {
|
||||
let vulkan_info = self.pci_info.as_ref().and_then(|pci_info| {
|
||||
match get_vulkan_info(
|
||||
&pci_info.device_pci_info.vendor_id,
|
||||
&pci_info.device_pci_info.model_id,
|
||||
) {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("could not load vulkan info: {err}");
|
||||
None
|
||||
fn get_info(&self, include_vulkan: bool) -> DeviceInfo {
|
||||
let vulkan_info = if include_vulkan {
|
||||
self.pci_info.as_ref().and_then(|pci_info| {
|
||||
match get_vulkan_info(
|
||||
&pci_info.device_pci_info.vendor_id,
|
||||
&pci_info.device_pci_info.model_id,
|
||||
) {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("could not load vulkan info: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let pci_info = self.pci_info.clone();
|
||||
let driver = self.handle.get_driver().to_owned();
|
||||
let vbios_version = self.get_full_vbios_version();
|
||||
@ -601,10 +609,6 @@ impl GpuController for AmdGpuController {
|
||||
}
|
||||
}
|
||||
|
||||
fn hw_monitors(&self) -> &[HwMon] {
|
||||
&self.handle.hw_monitors
|
||||
}
|
||||
|
||||
fn get_pci_slot_name(&self) -> Option<String> {
|
||||
self.handle.get_pci_slot_name().map(str::to_owned)
|
||||
}
|
||||
|
213
lact-daemon/src/server/gpu_controller/intel.rs
Normal file
213
lact-daemon/src/server/gpu_controller/intel.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use super::GpuController;
|
||||
use crate::{config, server::vulkan::get_vulkan_info};
|
||||
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
||||
use anyhow::anyhow;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use lact_schema::{
|
||||
ClocksInfo, ClockspeedStats, DeviceInfo, DeviceStats, GpuPciInfo, LinkInfo, PowerStates,
|
||||
};
|
||||
use std::{
|
||||
fmt::Display,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
enum DriverType {
|
||||
Xe,
|
||||
I915,
|
||||
}
|
||||
|
||||
pub struct IntelGpuController {
|
||||
sysfs_path: PathBuf,
|
||||
driver: String,
|
||||
driver_type: DriverType,
|
||||
pci_slot_id: Option<String>,
|
||||
pci_info: GpuPciInfo,
|
||||
tile_gts: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl IntelGpuController {
|
||||
pub fn new(
|
||||
sysfs_path: PathBuf,
|
||||
driver: String,
|
||||
pci_slot_id: Option<String>,
|
||||
pci_info: GpuPciInfo,
|
||||
) -> Self {
|
||||
let driver_type = match driver.as_str() {
|
||||
"xe" => DriverType::Xe,
|
||||
"i915" => DriverType::I915,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut tile_gts = vec![];
|
||||
|
||||
if let DriverType::Xe = driver_type {
|
||||
for entry in fs::read_dir(&sysfs_path).into_iter().flatten().flatten() {
|
||||
if let Some(name) = entry.file_name().to_str() {
|
||||
if name.starts_with("tile") {
|
||||
for gt_entry in fs::read_dir(entry.path()).into_iter().flatten().flatten() {
|
||||
if let Some(gt_name) = gt_entry.file_name().to_str() {
|
||||
if gt_name.starts_with("gt") {
|
||||
tile_gts.push(gt_entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
"initialized {} gt at '{}'",
|
||||
tile_gts.len(),
|
||||
sysfs_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
sysfs_path,
|
||||
driver,
|
||||
driver_type,
|
||||
pci_slot_id,
|
||||
pci_info,
|
||||
tile_gts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuController for IntelGpuController {
|
||||
fn get_id(&self) -> anyhow::Result<String> {
|
||||
let GpuPciInfo {
|
||||
device_pci_info,
|
||||
subsystem_pci_info,
|
||||
} = &self.pci_info;
|
||||
|
||||
Ok(format!(
|
||||
"{}:{}-{}:{}-{}",
|
||||
device_pci_info.vendor_id,
|
||||
device_pci_info.model_id,
|
||||
subsystem_pci_info.vendor_id,
|
||||
subsystem_pci_info.model_id,
|
||||
self.pci_slot_id.as_deref().unwrap_or("unknown-slot")
|
||||
))
|
||||
}
|
||||
|
||||
fn get_pci_info(&self) -> Option<&GpuPciInfo> {
|
||||
Some(&self.pci_info)
|
||||
}
|
||||
|
||||
fn get_path(&self) -> &Path {
|
||||
&self.sysfs_path
|
||||
}
|
||||
|
||||
fn get_info(&self, include_vulkan: bool) -> DeviceInfo {
|
||||
let vulkan_info = if include_vulkan {
|
||||
match get_vulkan_info(
|
||||
&self.pci_info.device_pci_info.vendor_id,
|
||||
&self.pci_info.device_pci_info.model_id,
|
||||
) {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("could not load vulkan info: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
DeviceInfo {
|
||||
pci_info: Some(self.pci_info.clone()),
|
||||
vulkan_info,
|
||||
driver: self.driver.clone(),
|
||||
vbios_version: None,
|
||||
link_info: LinkInfo::default(),
|
||||
drm_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pci_slot_name(&self) -> Option<String> {
|
||||
self.pci_slot_id.clone()
|
||||
}
|
||||
|
||||
fn apply_config<'a>(
|
||||
&'a self,
|
||||
_config: &'a config::Gpu,
|
||||
) -> LocalBoxFuture<'a, anyhow::Result<()>> {
|
||||
Box::pin(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn get_stats(&self, _gpu_config: Option<&config::Gpu>) -> DeviceStats {
|
||||
let current_gfxclk = self.read_gt_file("freq0/cur_freq");
|
||||
|
||||
let clockspeed = ClockspeedStats {
|
||||
gpu_clockspeed: self
|
||||
.read_gt_file("freq0/act_freq")
|
||||
.filter(|freq| *freq != 0)
|
||||
.or_else(|| current_gfxclk.map(u64::from)),
|
||||
current_gfxclk,
|
||||
vram_clockspeed: None,
|
||||
};
|
||||
|
||||
DeviceStats {
|
||||
clockspeed,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_clocks_info(&self) -> anyhow::Result<ClocksInfo> {
|
||||
Err(anyhow!("Not supported"))
|
||||
}
|
||||
|
||||
fn get_power_states(&self, _gpu_config: Option<&config::Gpu>) -> PowerStates {
|
||||
PowerStates::default()
|
||||
}
|
||||
|
||||
fn reset_pmfw_settings(&self) {}
|
||||
|
||||
fn cleanup_clocks(&self) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_power_profile_modes(&self) -> anyhow::Result<PowerProfileModesTable> {
|
||||
Err(anyhow!("Not supported"))
|
||||
}
|
||||
|
||||
fn vbios_dump(&self) -> anyhow::Result<Vec<u8>> {
|
||||
Err(anyhow!("Not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntelGpuController {
|
||||
fn first_tile_gt(&self) -> Option<&Path> {
|
||||
self.tile_gts.first().map(PathBuf::as_ref)
|
||||
}
|
||||
|
||||
fn read_gt_file<T>(&self, file_name: &str) -> Option<T>
|
||||
where
|
||||
T: FromStr,
|
||||
T::Err: Display,
|
||||
{
|
||||
if let Some(file_path) = self.first_tile_gt().map(|path| path.join(file_name)) {
|
||||
if file_path.exists() {
|
||||
match fs::read_to_string(&file_path) {
|
||||
Ok(contents) => match contents.trim().parse() {
|
||||
Ok(value) => return Some(value),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"could not parse value from '{}': {err}",
|
||||
file_path.display()
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
error!("could not read file at '{}': {err}", file_path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
mod amd;
|
||||
pub mod fan_control;
|
||||
mod intel;
|
||||
mod nvidia;
|
||||
|
||||
pub use amd::AmdGpuController;
|
||||
pub use intel::IntelGpuController;
|
||||
pub use nvidia::NvidiaGpuController;
|
||||
|
||||
use crate::config::{self};
|
||||
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
||||
use amdgpu_sysfs::hw_mon::HwMon;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use lact_schema::{ClocksInfo, DeviceInfo, DeviceStats, GpuPciInfo, PowerStates};
|
||||
use std::{path::Path, rc::Rc};
|
||||
@ -23,7 +24,7 @@ pub trait GpuController {
|
||||
|
||||
fn get_path(&self) -> &Path;
|
||||
|
||||
fn get_info(&self) -> DeviceInfo;
|
||||
fn get_info(&self, include_vulkan: bool) -> DeviceInfo;
|
||||
|
||||
fn get_pci_slot_name(&self) -> Option<String>;
|
||||
|
||||
@ -45,6 +46,4 @@ pub trait GpuController {
|
||||
fn get_power_profile_modes(&self) -> anyhow::Result<PowerProfileModesTable>;
|
||||
|
||||
fn vbios_dump(&self) -> anyhow::Result<Vec<u8>>;
|
||||
|
||||
fn hw_monitors(&self) -> &[HwMon];
|
||||
}
|
||||
|
@ -4,10 +4,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{fan_control::FanCurve, FanControlHandle, GpuController};
|
||||
use amdgpu_sysfs::{
|
||||
gpu_handle::power_profile_mode::PowerProfileModesTable,
|
||||
hw_mon::{HwMon, Temperature},
|
||||
};
|
||||
use amdgpu_sysfs::{gpu_handle::power_profile_mode::PowerProfileModesTable, hw_mon::Temperature};
|
||||
use anyhow::{anyhow, Context};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use lact_schema::{
|
||||
@ -32,11 +29,11 @@ use tokio::{select, sync::Notify, time::sleep};
|
||||
use tracing::{debug, error, trace, warn};
|
||||
|
||||
pub struct NvidiaGpuController {
|
||||
pub nvml: Rc<Nvml>,
|
||||
pub pci_slot_id: String,
|
||||
pub pci_info: GpuPciInfo,
|
||||
pub sysfs_path: PathBuf,
|
||||
pub fan_control_handle: RefCell<Option<FanControlHandle>>,
|
||||
nvml: Rc<Nvml>,
|
||||
pci_slot_id: String,
|
||||
pci_info: GpuPciInfo,
|
||||
sysfs_path: PathBuf,
|
||||
fan_control_handle: RefCell<Option<FanControlHandle>>,
|
||||
|
||||
last_applied_gpc_offset: Cell<Option<i32>>,
|
||||
last_applied_mem_offset: Cell<Option<i32>>,
|
||||
@ -275,18 +272,22 @@ impl GpuController for NvidiaGpuController {
|
||||
&self.sysfs_path
|
||||
}
|
||||
|
||||
fn get_info(&self) -> DeviceInfo {
|
||||
fn get_info(&self, include_vulkan: bool) -> DeviceInfo {
|
||||
let device = self.device();
|
||||
|
||||
let vulkan_info = match get_vulkan_info(
|
||||
&self.pci_info.device_pci_info.vendor_id,
|
||||
&self.pci_info.device_pci_info.model_id,
|
||||
) {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("could not load vulkan info: {err}");
|
||||
None
|
||||
let vulkan_info = if include_vulkan {
|
||||
match get_vulkan_info(
|
||||
&self.pci_info.device_pci_info.vendor_id,
|
||||
&self.pci_info.device_pci_info.model_id,
|
||||
) {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("could not load vulkan info: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
DeviceInfo {
|
||||
@ -353,10 +354,6 @@ impl GpuController for NvidiaGpuController {
|
||||
}
|
||||
}
|
||||
|
||||
fn hw_monitors(&self) -> &[HwMon] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn get_pci_slot_name(&self) -> Option<String> {
|
||||
Some(self.pci_slot_id.clone())
|
||||
}
|
||||
|
@ -6,13 +6,12 @@ use super::{
|
||||
use crate::{
|
||||
config::{self, default_fan_static_speed, Config, FanControlSettings, Profile},
|
||||
server::{
|
||||
gpu_controller::{AmdGpuController, NvidiaGpuController},
|
||||
gpu_controller::{AmdGpuController, IntelGpuController, NvidiaGpuController},
|
||||
profiles,
|
||||
},
|
||||
};
|
||||
use amdgpu_sysfs::{
|
||||
gpu_handle::{power_profile_mode::PowerProfileModesTable, PerformanceLevel, PowerLevelKind},
|
||||
sysfs::SysFS,
|
||||
use amdgpu_sysfs::gpu_handle::{
|
||||
power_profile_mode::PowerProfileModesTable, PerformanceLevel, PowerLevelKind,
|
||||
};
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use lact_schema::{
|
||||
@ -85,8 +84,6 @@ const SNAPSHOT_FAN_CTRL_FILES: &[&str] = &[
|
||||
"fan_zero_rpm_enable",
|
||||
"fan_zero_rpm_stop_temperature",
|
||||
];
|
||||
const SNAPSHOT_HWMON_FILE_PREFIXES: &[&str] =
|
||||
&["fan", "pwm", "power", "temp", "freq", "in", "name"];
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Handler {
|
||||
@ -355,7 +352,7 @@ impl<'a> Handler {
|
||||
}
|
||||
|
||||
pub fn get_device_info(&'a self, id: &str) -> anyhow::Result<DeviceInfo> {
|
||||
Ok(self.controller_by_id(id)?.get_info())
|
||||
Ok(self.controller_by_id(id)?.get_info(true))
|
||||
}
|
||||
|
||||
pub fn get_gpu_stats(&'a self, id: &str) -> anyhow::Result<DeviceStats> {
|
||||
@ -607,31 +604,33 @@ impl<'a> Handler {
|
||||
}
|
||||
}
|
||||
|
||||
let card_path = controller.get_path().parent().unwrap();
|
||||
let card_files = fs::read_dir(card_path)
|
||||
.context("Could not read device dir")?
|
||||
.flatten();
|
||||
for card_entry in card_files {
|
||||
if let Ok(metadata) = card_entry.metadata() {
|
||||
if metadata.is_file() {
|
||||
let full_path = controller_path.join(card_entry.path());
|
||||
add_path_to_archive(&mut archive, &full_path)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let gt_path = card_path.join("gt");
|
||||
if gt_path.exists() {
|
||||
add_path_recursively(&mut archive, >_path, card_path)?;
|
||||
}
|
||||
|
||||
let fan_ctrl_path = controller_path.join("gpu_od").join("fan_ctrl");
|
||||
for fan_ctrl_file in SNAPSHOT_FAN_CTRL_FILES {
|
||||
let full_path = fan_ctrl_path.join(fan_ctrl_file);
|
||||
add_path_to_archive(&mut archive, &full_path)?;
|
||||
}
|
||||
|
||||
for hw_mon in controller.hw_monitors() {
|
||||
let hw_mon_path = hw_mon.get_path();
|
||||
let hw_mon_entries =
|
||||
fs::read_dir(hw_mon_path).context("Could not read HwMon dir")?;
|
||||
|
||||
'entries: for entry in hw_mon_entries.flatten() {
|
||||
if !entry.metadata().is_ok_and(|metadata| metadata.is_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(name) = entry.file_name().to_str() {
|
||||
for prefix in SNAPSHOT_HWMON_FILE_PREFIXES {
|
||||
if name.starts_with(prefix) {
|
||||
add_path_to_archive(&mut archive, &entry.path())?;
|
||||
continue 'entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let hwmon_path = controller_path.join("hwmon");
|
||||
if hwmon_path.exists() {
|
||||
add_path_recursively(&mut archive, &hwmon_path, controller_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -671,7 +670,7 @@ impl<'a> Handler {
|
||||
let info = json!({
|
||||
"system_info": system_info,
|
||||
"initramfs_type": initramfs_type,
|
||||
"devices": self.generate_snapshot_device_info(),
|
||||
"devices": self.generate_snapshot_device_info(true),
|
||||
});
|
||||
let info_data = serde_json::to_vec_pretty(&info).unwrap();
|
||||
|
||||
@ -696,7 +695,10 @@ impl<'a> Handler {
|
||||
Ok(out_path)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_snapshot_device_info(&self) -> BTreeMap<String, serde_json::Value> {
|
||||
pub(crate) fn generate_snapshot_device_info(
|
||||
&self,
|
||||
include_vulkan: bool,
|
||||
) -> BTreeMap<String, serde_json::Value> {
|
||||
self.gpu_controllers
|
||||
.iter()
|
||||
.map(|(id, controller)| {
|
||||
@ -708,7 +710,7 @@ impl<'a> Handler {
|
||||
|
||||
let data = json!({
|
||||
"pci_info": controller.get_pci_info(),
|
||||
"info": controller.get_info(),
|
||||
"info": controller.get_info(include_vulkan),
|
||||
"stats": controller.get_stats(gpu_config),
|
||||
"clocks_info": controller.get_clocks_info().ok(),
|
||||
"power_profile_modes": controller.get_power_profile_modes().ok(),
|
||||
@ -965,6 +967,27 @@ fn load_controllers(
|
||||
Ok(id) => {
|
||||
let path = controller.get_path();
|
||||
|
||||
if matches!(controller.get_driver(), "xe" | "i915") {
|
||||
match controller.get_pci_info() {
|
||||
Some(pci_info) => {
|
||||
let controller = IntelGpuController::new(
|
||||
path.to_owned(),
|
||||
controller.get_driver().to_owned(),
|
||||
controller.get_pci_slot_name(),
|
||||
pci_info.clone(),
|
||||
);
|
||||
let id = controller.get_id().unwrap();
|
||||
info!("initialized Intel controller {id} for path {path:?}");
|
||||
controllers
|
||||
.insert(id, Box::new(controller) as Box<dyn GpuController>);
|
||||
continue;
|
||||
}
|
||||
None => {
|
||||
error!("could not get PCI info for Intel GPU at {path:?}",);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(nvml) = nvml.clone() {
|
||||
if let Some(pci_slot_id) = controller.get_pci_slot_name() {
|
||||
match nvml.device_by_pci_bus_id(pci_slot_id.as_str()) {
|
||||
@ -1082,6 +1105,8 @@ fn add_path_to_archive(
|
||||
warn!("file {full_path:?} exists, but could not be added to snapshot: {err}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace!("{full_path:?} does not exist, not adding to snapshot");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
1
lact-daemon/src/tests/data/intel/cometlake/card0/dev
Normal file
1
lact-daemon/src/tests/data/intel/cometlake/card0/dev
Normal file
@ -0,0 +1 @@
|
||||
226:0
|
@ -0,0 +1 @@
|
||||
Unknown
|
@ -0,0 +1 @@
|
||||
0
|
@ -0,0 +1,6 @@
|
||||
DRIVER=i915
|
||||
PCI_CLASS=30000
|
||||
PCI_ID=8086:9B41
|
||||
PCI_SUBSYS_ID=17AA:22B1
|
||||
PCI_SLOT_NAME=0000:00:02.0
|
||||
MODALIAS=pci:v00008086d00009B41sv000017AAsd000022B1bc03sc00i00
|
@ -0,0 +1 @@
|
||||
0x8086
|
@ -0,0 +1 @@
|
||||
1150
|
@ -0,0 +1 @@
|
||||
300
|
@ -0,0 +1 @@
|
||||
300
|
@ -0,0 +1 @@
|
||||
300
|
@ -0,0 +1 @@
|
||||
1150
|
@ -0,0 +1 @@
|
||||
300
|
@ -0,0 +1 @@
|
||||
1150
|
@ -0,0 +1 @@
|
||||
300
|
4
lact-daemon/src/tests/data/intel/cometlake/card0/uevent
Normal file
4
lact-daemon/src/tests/data/intel/cometlake/card0/uevent
Normal file
@ -0,0 +1,4 @@
|
||||
MAJOR=226
|
||||
MINOR=0
|
||||
DEVNAME=dri/card0
|
||||
DEVTYPE=drm_minor
|
@ -0,0 +1 @@
|
||||
Unknown
|
@ -0,0 +1 @@
|
||||
0
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
10000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
5000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
640000
|
@ -0,0 +1 @@
|
||||
10000000
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1 @@
|
||||
1000
|
@ -0,0 +1 @@
|
||||
0
|
@ -0,0 +1 @@
|
||||
1100
|
@ -0,0 +1 @@
|
||||
1300
|
@ -0,0 +1 @@
|
||||
1100
|
@ -0,0 +1 @@
|
||||
1300
|
@ -0,0 +1 @@
|
||||
600
|
@ -0,0 +1 @@
|
||||
100
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user