我在Linux上有一个C ++应用程序,它对延迟非常敏感。我的内存使用量约为2GB,因此有4kb页面和64个TLB条目,我将遇到TLB未命中。
我在英特尔开发人员手册中读到2MB(或4MB?)“巨大”页面只能将TLB条目的数量减少一半,因此内存范围的增加抵消了TLB条目的减少,并且性能会更好
如何在C ++应用程序中使用“巨大”页面分配内存?我应该注意哪些权衡取舍?
我的Linux是Red Hat发行版。
答案 0 :(得分:7)
我假设您只需要为使用C ++编写的特定应用程序提供大页面,否则您只需更改系统的页面大小。以下方法适用于以任何语言编写的应用程序。
为了在特定应用程序中使用大页面,您需要构建内核以支持大页面支持。您必须使用CONFIG_HUGETLBFS
选项
通过指定
指定页面大小hugepagesz=<size>
在启动命令行上
要了解如何设置启动参数:http://www.cyberciti.biz/tips/10-boot-time-parameters-you-should-know-about-the-linux-kernel.html
要设置大页面的数量,请使用
# echo 20 > /proc/sys/vm/nr_hugepages
检查大页面(可用,总计......)
# cat /proc/meminfo
当以上所有情况都很好时,现在您必须使用“如何将这些页面用于特定应用程序”:将hugetlbfs
类型的文件系统挂载为
# mount -t hugetlbfs -o uid=<value>,gid=<value>,mode=<value>,pagesize=<value>,size=<value>,min_size=<value>,nr_inodes=<value> none /mnt/huge
将您的应用程序放在此挂载/mnt/huge
繁荣上,现在您的应用程序将使用您设置的页面大小!
有关详细信息,请查看https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
大页面的优点/缺点:
优点:由于TLB未命中减少,页面错误减少,页面大小减少以及翻译量减少而提高效率
缺点:更多的内部碎片:内存丢失,交换延迟更多(HUGETLBFS
页面不会刷出他们的映射是永久性的)
有关详情,请查看https://lwn.net/Articles/359158/
修改强> 还有API可用于分配大页面plz检查也许它有帮助
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/HOWTO
答案 1 :(得分:6)
"hugetlb" documentation from the kernel应该有帮助。
用户可以通过使用mmap系统调用或标准SYSV共享内存系统调用(shmget,shmat)来使用Linux内核中的大页面支持。
和
实施例
1)map_hugetlb:参见tools / testing / selftests / vm / map_hugetlb.c
2)hugepage-shm:参见tools / testing / selftests / vm / hugepage-shm.c
3)hugepage-mmap:参见tools / testing / selftests / vm / hugepage-mmap.c
4)libhugetlbfs(https://github.com/libhugetlbfs/libhugetlbfs)库 提供广泛的用户空间工具,以帮助实现巨大的页面和可用性, 环境设置和控制。
(这些路径指的是linux源代码树)。
所以它基本归结为:
mmap
与MAP_HUGETLB
标志答案 2 :(得分:3)
您还可以尝试使用过去几年中任何内核上可用的transparent huge page support(至少3.x和4.x范围内的任何内核以及各种2.6.x内核)。
主要的好处是你不需要任何特殊的&#34; hugetlbfs&#34;设置,它只是工作&#34;。缺点是它有保证:内核可能满足您的分配大页面如果满足某些条件且有些条件可用。与hugetlbfs
不同,/sys/kernel/mm/transparent_hugepage/enabled
在启动时保留固定数量的大页面,这些页面仅通过特定调用可用,透明的大页面可以从一般内存池中分割出大量页面。这需要连续的2MB物理内存块,由于物理内存碎片,这些块可能会随着时间的推移而变得罕见。
此外,还有各种内核可调参数会影响您是否获得大页面,其中最重要的是posix_memalign
。
最好的选择是使用madvise(MADV_HUGEPAGE)
在2MB边界上分配块,然后在分配区域之前执行aligned_alloc
触摸它首次。它也适用于/sys/kernel/mm/transparent_hugepage/enabled
等变体。根据我的经验,在always
设置为malloc
的系统上,这通常会导致巨大的页面。但是,我主要用于具有大量可用内存且运行时间不太长的系统。
如果您使用的是2GB内存,则可能会从大页面中获得显着的好处。如果您将所有内容分配为小块,例如通过 package com.example.hp.healthcareapp;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.basgeekball.awesomevalidation.AwesomeValidation;
import com.basgeekball.awesomevalidation.ValidationStyle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class Registrationadmin extends AppCompatActivity {
private EditText Nameadm, Emailadm, Passadm, Mobadm;
private Button Registeradm;
private AwesomeValidation awesomeValidation;
String Name, Email, Password, Mob;
Context ctx = this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registrationadmin);
awesomeValidation = new AwesomeValidation(ValidationStyle.BASIC);
Nameadm = (EditText) findViewById(R.id.etnameadm);
Emailadm = (EditText) findViewById(R.id.etemailadm);
Passadm = (EditText) findViewById(R.id.etpassadm);
Mobadm = (EditText) findViewById(R.id.etmobadm);
Registeradm = (Button) findViewById(R.id.btnregisteradm);
awesomeValidation.addValidation(this, R.id.etnameadm, "^[A-Za-z\\s]{1,}[\\.]{0,1}[A-Za-z\\s]{0,}$", R.string.nameerror);
awesomeValidation.addValidation(this, R.id.etemailadm, Patterns.EMAIL_ADDRESS, R.string.emailerror);
// awesomeValidation.addValidation(this, R.id.etpasspat, "^[A-Za-z\\s]{1,}[\\.]{0,1}[A-Za-z\\s]{0,}$", R.string.passworderror);
awesomeValidation.addValidation(this, R.id.etmobadm, "^[+]??[0-9]{10,13}$", R.string.mobileerror);
//awesomeValidation.addValidation(this, R.id.etmobpat, RegexTemplate.TELEPHONE, R.string.mobileerror);
//awesomeValidation.addValidation(this, R.id.etaddadm, "^[A-Za-z\\s]{1,}[\\.]{0,1}[A-Za-z\\s]{0,}$", R.string.adderror);
String regexPassword = "(?=.*[a-z])(?=.*[A-Z])(?=.*[\\d])(?=.*[~`!@#\\$%\\^&\\*\\(\\)\\-_\\+=\\{\\}\\[\\]\\|\\;:\"<>,./\\?]).{8,}";
awesomeValidation.addValidation(this, R.id.etpassadm, regexPassword, R.string.passworderror);
}
public void btnregisteradm(View v) {
if (awesomeValidation.validate()) {
Name = Nameadm.getText().toString();
Password = Passadm.getText().toString();
Email = Emailadm.getText().toString();
Mob = Mobadm.getText().toString();
//Toast.makeText(ctx, "we are here", Toast.LENGTH_SHORT).show();
BackGround b = new BackGround();
//Toast.makeText(ctx, "we are here", Toast.LENGTH_SHORT).show();
b.execute(Name, Password, Email, Mob);
//Toast.makeText(ctx, "we are here", Toast.LENGTH_SHORT).show();
}
}
static class BackGround extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... params) {
String admname = params[0];
String admpassword = params[1];
String admemail = params[2];
String admmob = params[3];
String data = "";
int tmp;
try {
URL url = new URL("http://10.14.83.2:8080/register.php");
String urlParams = "admname=" + admname + "&admemail=" + admemail + "&admpassword=" + admpassword + "&admmob=" + admmob;
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoOutput(true);
OutputStream os = httpURLConnection.getOutputStream();
os.write(urlParams.getBytes());
os.flush();
os.close();
Log.d("executes", "this is executed");
InputStream is = httpURLConnection.getInputStream();
Log.d("problem", "this line is not executed");
while ((tmp = is.read()) != -1) {
data += (char) tmp;
}
Log.d("problem8", "why is this error");
is.close();
httpURLConnection.disconnect();
return data;
} catch (MalformedURLException e1) {
e1.printStackTrace();
Log.d("IOEX1", e1.getMessage());
return "Exception: " + e1.getMessage();
} catch (IOException e) {
e.printStackTrace();
Log.d("IOEX3", e.getMessage());
return "Exception: " + e.getMessage();
}
}
@Override
protected void onPostExecute(String s) {
if(s.equals("")){
s="Data saved successfully.";
}
}
}}
,很有可能透明的大页面无法启动,因此您也可以考虑以THP感知方式分配任何使用大量内存的内容(通常是单个对象类型) 。
我还写了a library以确定你是否从任何给定的分配中获得了大量的。这可能在生产应用程序中并不常用,但如果您尝试使用THP,它可能是一个有用的诊断,因为至少您可以确定是否得到它们。