開發環境
操作系統: openkylin2qt版本 : 5.15.10
排查過程
????????首先看下問題的現象,
問題現象
????????
? ? ? 復現問題的demo很簡單,只能是從跟蹤qt代碼方面入手
void MainWindow::on_pushButton_clicked(){QPrinter printer;QPrintDialog dialog(&printer,this);dialog.exec();}
????????現在需要找一個代碼的起點去跟蹤,想了半天沒有思緒,于是設置環境變量export QT_DEBUG_PLUGINS=1看看有沒有提示,結果發現程序會在這一行阻塞一段時間
load library "xxx/plugins/printsupport/libcupsprintersupport.so"
? ? ? ? 懷疑可能與加載libcupsprintersupport.so庫有關,可以從QLibrary加載插件庫的代碼開始查,經過gdb+打日志雙重定位下,找到了耗時的代碼范圍
//這個函數在運行過程中被調用了多次QPrinterInfo QPrinterPrivate::findValidPrinter(const QPrinterInfo &printer){// Try find a valid printer to use, either the one given, the default or the first availableQPrinterInfo printerToUse = printer;if (printerToUse.isNull()) {printerToUse = QPrinterInfo::defaultPrinter(); //調用耗時1秒if (printerToUse.isNull()) {QStringList availablePrinterNames = QPrinterInfo::availablePrinterNames(); //調用耗時1秒if (!availablePrinterNames.isEmpty())printerToUse = QPrinterInfo::printerInfo(availablePrinterNames.at(0));}}return printerToUse;}//這個構造函數被調用了一次QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn): parent(p), propertiesDialog(nullptr), printer(prn),#if QT_CONFIG(cups)m_duplexPpdOption(nullptr),#endifoptionsPane(nullptr), filePrintersAdded(false){q = nullptr;if (parent)q = qobject_cast (parent->parent());widget.setupUi(parent);int currentPrinterIndex = 0;QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();if (ps) {const QStringList printers = ps->availablePrintDeviceIds(); //調用耗時1秒const QString defaultPrinter = ps->defaultPrintDeviceId(); //調用耗時1秒widget.printers->addItems(printers);const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;const int idx = printers.indexOf(selectedPrinter);if (idx >= 0)currentPrinterIndex = idx;}widget.properties->setEnabled(true);#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)QFileSystemModel *fsm = new QFileSystemModel(widget.filename);fsm->setRootPath(QDir::homePath());widget.filename->setCompleter(new QCompleter(fsm, widget.filename));#endif_q_printerChanged(currentPrinterIndex);QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),parent, SLOT(_q_printerChanged(int)));QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));// disable features that QPrinter does not yet support.widget.preview->setVisible(false);}//上面調用耗時的函數就是下面這兩個QStringList QCupsPrinterSupport::availablePrintDeviceIds() const{QStringList list;cups_dest_t *dests;int count = cupsGetDests(&dests); //調用耗時1秒list.reserve(count);for (int i = 0; i < count; ++i) {QString printerId = QString::fromLocal8Bit(dests[i].name);if (dests[i].instance)printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);list.append(printerId);}cupsFreeDests(count, dests);return list;}QString QCupsPrinterSupport::staticDefaultPrintDeviceId(){QString printerId;cups_dest_t *dests;int count = cupsGetDests(&dests); //調用耗時1秒for (int i = 0; i < count; ++i) {if (dests[i].is_default) {printerId = QString::fromLocal8Bit(dests[i].name);if (dests[i].instance) {printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);break;}}}cupsFreeDests(count, dests);return printerId;}
???????????????cupsGetDests是cups庫的api
(1) cups 是一個開放源代碼的打印系統,為Unix類操作系統(如Linux)提供了標準的打印架構。(2) libcupsprintersupport.so庫為qt開發者提供更便捷的api, libcupsprintersupport.so庫內部調用的還是cups庫api
????????????????
? ? ? ? ? ? ? ?我單獨寫了一個調用cups api的demo,進一步驗證是cupsGetDests耗時
#include < cups/cups.h >#include < iostream >#include < ctime >#include < sys/time.h >//編譯命令 g++ test.cpp -lcups/*開始 cupsGetDestsTimestamp (milliseconds): 1742524701156Timestamp (milliseconds): 1742524702187結束 cupsGetDests開始 cupsFreeDestsTimestamp (milliseconds): 1742524702187Timestamp (milliseconds): 1742524702187結束 cupsFreeDests*/void getime(){struct timeval tv;gettimeofday(&tv, nullptr);long timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;std::cout << "Timestamp (milliseconds): " << timestamp << std::endl;}int main() {// 獲取打印機列表cups_dest_t* dests = nullptr;std::cout << "開始 cupsGetDests" << std::endl;getime();int num_dests = cupsGetDests(&dests); //此處耗時大約1秒getime();std::cout << "結束 cupsGetDests" << std::endl;/*if (num_dests == 0) {std::cerr << "No printers found!" << std::endl;return 1;}*/// 遍歷打印機列表for (int i = 0; i < num_dests; i++) {cups_dest_t& dest = dests[i];// 打印打印機名稱std::cout << "Printer Name: " << dest.name << std::endl;// 打印打印機是否默認if (dest.is_default) {std::cout << " (Default Printer)" << std::endl;}// 打印打印機選項for (int j = 0; j < dest.num_options; j++) {std::cout << " Option: " << dest.options[j].name<< " = " << dest.options[j].value << std::endl;}std::cout << std::endl;}// 釋放打印機列表std::cout << "開始 cupsFreeDests" << std::endl;getime();cupsFreeDests(num_dests, dests);getime();std::cout << "結束 cupsFreeDests" << std::endl;return 0;}
排查結論
????????qt程序運行過程中使用cups庫的api,調用api耗時,導致qt組件彈出慢