Skip to content

Commit

Permalink
zram:calculate available memory when zram is used
Browse files Browse the repository at this point in the history
When zram is used, available+Swap free memory is obviously
bigger than we actually can use, because zram can compress
memory by compression algorithm and zram compressed data
will occupy memory too.

So, we can count the compression ratio of zram in the kernel.
The space will be saved by zram and other swap device are
calculated as follows:
zram[swapfree - swapfree * compress ratio] + swapdev[swapfree]
We can evaluate the available memory of the whole system as:
MemAvailable+zram[swapfree - swapfree * compress ratio]+swapdev[swapfree]

Add an entry to the /proc/meminfo file, returns swap will save space.
Which name is more appropriate is still under consideration.
There are several alternative names: SwapAvailable, SwapSaved,
SwapCompressible

Signed-off-by: wangyong <yongw.pur@gmail.com>
  • Loading branch information
wangyong authored and intel-lab-lkp committed Jun 5, 2021
1 parent 808d854 commit 0c03fad
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/block/zram/zcomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ int zcomp_decompress(struct zcomp_strm *zstrm,
const void *src, unsigned int src_len, void *dst);

bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
int get_zram_major(void);
#endif /* _ZCOMP_H_ */
19 changes: 19 additions & 0 deletions drivers/block/zram/zram_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ static void zram_free_page(struct zram *zram, size_t index);
static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
u32 index, int offset, struct bio *bio);

int get_zram_major(void)
{
return zram_major;
}

static int zram_slot_trylock(struct zram *zram, u32 index)
{
Expand Down Expand Up @@ -1040,6 +1044,19 @@ static ssize_t compact_store(struct device *dev,
return len;
}

static ssize_t min_compr_ratio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zram *zram = dev_to_zram(dev);
ssize_t ret;

down_read(&zram->init_lock);
ret = scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zram->stats.min_compr_ratio));
up_read(&zram->init_lock);

return ret;
}

static ssize_t io_stat_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
Expand Down Expand Up @@ -1132,6 +1149,7 @@ static ssize_t debug_stat_show(struct device *dev,
return ret;
}

static DEVICE_ATTR_RO(min_compr_ratio);
static DEVICE_ATTR_RO(io_stat);
static DEVICE_ATTR_RO(mm_stat);
#ifdef CONFIG_ZRAM_WRITEBACK
Expand Down Expand Up @@ -1859,6 +1877,7 @@ static struct attribute *zram_disk_attrs[] = {
&dev_attr_idle.attr,
&dev_attr_max_comp_streams.attr,
&dev_attr_comp_algorithm.attr,
&dev_attr_min_compr_ratio.attr,
#ifdef CONFIG_ZRAM_WRITEBACK
&dev_attr_backing_dev.attr,
&dev_attr_writeback.attr,
Expand Down
1 change: 1 addition & 0 deletions drivers/block/zram/zram_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct zram_stats {
atomic64_t bd_reads; /* no. of reads from backing device */
atomic64_t bd_writes; /* no. of writes from backing device */
#endif
atomic_t min_compr_ratio;
};

struct zram {
Expand Down
1 change: 1 addition & 0 deletions fs/proc/meminfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)

show_val_kb(m, "SwapTotal: ", i.totalswap);
show_val_kb(m, "SwapFree: ", i.freeswap);
show_val_kb(m, "SwapAvailable: ", count_avail_swaps());
show_val_kb(m, "Dirty: ",
global_node_page_state(NR_FILE_DIRTY));
show_val_kb(m, "Writeback: ",
Expand Down
10 changes: 10 additions & 0 deletions include/linux/swap.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ extern int init_swap_address_space(unsigned int type, unsigned long nr_pages);
extern void exit_swap_address_space(unsigned int type);
extern struct swap_info_struct *get_swap_device(swp_entry_t entry);
sector_t swap_page_sector(struct page *page);
extern void update_zram_zstats(void);
extern u64 count_avail_swaps(void);

static inline void put_swap_device(struct swap_info_struct *si)
{
Expand Down Expand Up @@ -665,6 +667,14 @@ static inline swp_entry_t get_swap_page(struct page *page)
return entry;
}

void update_zram_zstats(void)
{
}

u64 count_avail_swaps(void)
{
}

#endif /* CONFIG_SWAP */

#ifdef CONFIG_THP_SWAP
Expand Down
95 changes: 95 additions & 0 deletions mm/swapfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <asm/tlbflush.h>
#include <linux/swapops.h>
#include <linux/swap_cgroup.h>
#include "../drivers/block/zram/zram_drv.h"

static bool swap_count_continued(struct swap_info_struct *, pgoff_t,
unsigned char);
Expand Down Expand Up @@ -3392,6 +3393,100 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
return error;
}

u64 count_avail_swap(struct swap_info_struct *si)
{
u64 result;
struct zram *z;
unsigned int free;
unsigned int ratio;

result = 0;
if (!si)
return 0;

//zram calculate available mem
if (si->flags & SWP_USED && si->swap_map) {
if (si->bdev->bd_disk->major == get_zram_major()) {
z = (struct zram *)si->bdev->bd_disk->private_data;
down_read(&z->init_lock);
ratio = atomic_read(&z->stats.min_compr_ratio);
free = (si->pages << (PAGE_SHIFT - 10))
- (si->inuse_pages << (PAGE_SHIFT - 10));
if (!ratio)
result += free / 2;
else
result = free * (100 - 10000 / ratio) / 100;
up_read(&z->init_lock);
}
} else
result += (si->pages << (PAGE_SHIFT - 10))
- (si->inuse_pages << (PAGE_SHIFT - 10));

return result;
}

u64 count_avail_swaps(void)
{
int type;
u64 result;
struct swap_info_struct *si;

result = 0;
spin_lock(&swap_lock);
for (type = 0; type < nr_swapfiles; type++) {
si = swap_info[type];
spin_lock(&si->lock);
result += count_avail_swap(si);
spin_unlock(&si->lock);
}
spin_unlock(&swap_lock);

return result;
}

void update_zram_zstat(struct swap_info_struct *si)
{
struct zram *z;
struct zram_stats *stat;
int ratio;
u64 orig_size, compr_data_size;

if (!si)
return;

//update zram min compress ratio
if (si->flags & SWP_USED && si->swap_map) {
if (si->bdev->bd_disk->major == get_zram_major()) {
z = (struct zram *)si->bdev->bd_disk->private_data;
down_read(&z->init_lock);
stat = &z->stats;
ratio = atomic_read(&stat->min_compr_ratio);
orig_size = atomic64_read(&stat->pages_stored) << PAGE_SHIFT;
compr_data_size = atomic64_read(&stat->compr_data_size);
if (compr_data_size && (!ratio
|| ((orig_size * 100) / compr_data_size < ratio)))
atomic_set(&stat->min_compr_ratio,
(orig_size * 100) / compr_data_size);
up_read(&z->init_lock);
}
}
}

void update_zram_zstats(void)
{
int type;
struct swap_info_struct *si;

spin_lock(&swap_lock);
for (type = 0; type < nr_swapfiles; type++) {
si = swap_info[type];
spin_lock(&si->lock);
update_zram_zstat(si);
spin_unlock(&si->lock);
}
spin_unlock(&swap_lock);
}

void si_swapinfo(struct sysinfo *val)
{
unsigned int type;
Expand Down
1 change: 1 addition & 0 deletions mm/vmscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -4124,6 +4124,7 @@ static int kswapd(void *p)
alloc_order);
reclaim_order = balance_pgdat(pgdat, alloc_order,
highest_zoneidx);
update_zram_zstats();
if (reclaim_order < alloc_order)
goto kswapd_try_sleep;
}
Expand Down

0 comments on commit 0c03fad

Please sign in to comment.